using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using ScrewTurn.Wiki.PluginFramework; using System.Text; namespace ScrewTurn.Wiki { public partial class DefaultPage : BasePage { private PageInfo currentPage = null; private PageContent currentContent = null; private bool discussMode = false; private bool viewCodeMode = false; protected void Page_Load(object sender, EventArgs e) { discussMode = Request["Discuss"] != null; viewCodeMode = Request["Code"] != null && !discussMode; if(!Settings.EnableViewPageCodeFeature) viewCodeMode = false; currentPage = DetectPageInfo(true); VerifyAndPerformRedirects(); // The following actions are verified: // - View content (redirect to AccessDenied) // - Edit or Edit with Approval (for button display) // - Any Administrative activity (Rollback/Admin/Perms) (for button display) // - Download attachments (for button display - download permissions are also checked in GetFile) // - View discussion (for button display in content mode) // - Post discussion (for button display in discuss mode) string currentUsername = SessionFacade.GetCurrentUsername(); string[] currentGroups = SessionFacade.GetCurrentGroupNames(); bool canView = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ReadPage, currentUsername, currentGroups); bool canEdit = false; bool canEditWithApproval = false; Pages.CanEditPage(currentPage, currentUsername, currentGroups, out canEdit, out canEditWithApproval); if(canEditWithApproval && canEdit) canEditWithApproval = false; bool canDownloadAttachments = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.DownloadAttachments, currentUsername, currentGroups); bool canSetPerms = AuthChecker.CheckActionForGlobals(Actions.ForGlobals.ManagePermissions, currentUsername, currentGroups); bool canAdmin = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ManagePage, currentUsername, currentGroups); bool canViewDiscussion = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ReadDiscussion, currentUsername, currentGroups); bool canPostDiscussion = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.PostDiscussion, currentUsername, currentGroups); bool canManageDiscussion = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ManageDiscussion, currentUsername, currentGroups); if(!canView) { if(SessionFacade.LoginKey == null) UrlTools.Redirect("Login.aspx?Redirect=" + Tools.UrlEncode(Request.Url.ToString())); else UrlTools.Redirect(UrlTools.BuildUrl("AccessDenied.aspx")); } attachmentViewer.Visible = canDownloadAttachments; attachmentViewer.PageInfo = currentPage; currentContent = Content.GetPageContent(currentPage, true); pnlPageInfo.Visible = Settings.EnablePageInfoDiv; SetupTitles(); SetupToolbarLinks(canEdit || canEditWithApproval, canViewDiscussion, canPostDiscussion, canDownloadAttachments, canAdmin, canAdmin, canSetPerms); SetupLabels(); SetupPrintAndRssLinks(); SetupMetaInformation(); VerifyAndPerformPageRedirection(); SetupRedirectionSource(); SetupNavigationPaths(); SetupAdjacentPages(); SessionFacade.Breadcrumbs.AddPage(currentPage); SetupBreadcrumbsTrail(); SetupDoubleClickHandler(); SetupEmailNotification(); SetupPageContent(canPostDiscussion, canManageDiscussion); } /// /// Verifies the need for a redirect and performs it. /// private void VerifyAndPerformRedirects() { if(currentPage == null) { UrlTools.Redirect(UrlTools.BuildUrl("PageNotFound.aspx?Page=", Tools.UrlEncode(DetectFullName()))); } if(Request["Edit"] == "1") { UrlTools.Redirect(UrlTools.BuildUrl("Edit.aspx?Page=", Tools.UrlEncode(currentPage.FullName))); } if(Request["History"] == "1") { UrlTools.Redirect(UrlTools.BuildUrl("History.aspx?Page=", Tools.UrlEncode(currentPage.FullName))); } } /// /// Sets the titles used in the page. /// private void SetupTitles() { string title = FormattingPipeline.PrepareTitle(currentContent.Title, false, FormattingContext.PageContent, currentPage); Page.Title = title + " - " + Settings.WikiTitle; lblPageTitle.Text = title; } /// /// Sets the content and visibility of all toolbar links. /// /// A value indicating whether the current user can edit the page. /// A value indicating whether the current user can view the page discussion. /// A value indicating whether the current user can post messages in the page discussion. /// A value indicating whether the current user can download attachments. /// A value indicating whether the current user can rollback the page. /// A value indicating whether the current user can perform at least one administration task. /// A value indicating whether the current user can set page permissions. private void SetupToolbarLinks(bool canEdit, bool canViewDiscussion, bool canPostMessages, bool canDownloadAttachments, bool canRollback, bool canAdmin, bool canSetPerms) { lblDiscussLink.Visible = !discussMode && !viewCodeMode && canViewDiscussion; if(lblDiscussLink.Visible) { lblDiscussLink.Text = string.Format(@"{1} ({2})", Properties.Messages.Discuss, Properties.Messages.Discuss, Pages.GetMessageCount(currentPage)); } lblEditLink.Visible = Settings.EnablePageToolbar && !discussMode && !viewCodeMode && canEdit; if(lblEditLink.Visible) { lblEditLink.Text = string.Format(@"{2}", Properties.Messages.EditThisPage, UrlTools.BuildUrl("Edit.aspx?Page=", Tools.UrlEncode(currentPage.FullName)), Properties.Messages.Edit); } if(Settings.EnablePageToolbar && Settings.EnableViewPageCodeFeature) { lblViewCodeLink.Visible = !discussMode && !viewCodeMode && !canEdit; if(lblViewCodeLink.Visible) { lblViewCodeLink.Text = string.Format(@"{1}", Properties.Messages.ViewPageCode, Properties.Messages.ViewPageCode); } } else lblViewCodeLink.Visible = false; lblHistoryLink.Visible = Settings.EnablePageToolbar && !discussMode && !viewCodeMode && canViewDiscussion; if(lblHistoryLink.Visible) { lblHistoryLink.Text = string.Format(@"{2}", Properties.Messages.ViewPageHistory, UrlTools.BuildUrl("History.aspx?Page=", Tools.UrlEncode(currentPage.FullName)), Properties.Messages.History); } int attachmentCount = GetAttachmentCount(); lblAttachmentsLink.Visible = canDownloadAttachments && !discussMode && !viewCodeMode && attachmentCount > 0; if(lblAttachmentsLink.Visible) { lblAttachmentsLink.Text = string.Format(@"{1}", Properties.Messages.Attachments, Properties.Messages.Attachments); } attachmentViewer.Visible = lblAttachmentsLink.Visible; int bakCount = GetBackupCount(); lblAdminToolsLink.Visible = Settings.EnablePageToolbar && !discussMode && !viewCodeMode && ((canRollback && bakCount > 0)|| canAdmin || canSetPerms); if(lblAdminToolsLink.Visible) { lblAdminToolsLink.Text = string.Format(@"{1}", Properties.Messages.AdminTools, Properties.Messages.Admin); if(canRollback && bakCount > 0) { lblRollbackPage.Text = string.Format(@"{2}", Tools.UrlEncode(currentPage.FullName), Properties.Messages.RollbackThisPage, Properties.Messages.Rollback); } else lblRollbackPage.Visible = false; if(canAdmin) { lblAdministratePage.Text = string.Format(@"{2}", Tools.UrlEncode(currentPage.FullName), Properties.Messages.AdministrateThisPage, Properties.Messages.Administrate); } else lblAdministratePage.Visible = false; if(canSetPerms) { lblSetPagePermissions.Text = string.Format(@"{2}", Tools.UrlEncode(currentPage.FullName), Properties.Messages.SetPermissionsForThisPage, Properties.Messages.Permissions); } else lblSetPagePermissions.Visible = false; } lblPostMessageLink.Visible = discussMode && !viewCodeMode && canPostMessages; if(lblPostMessageLink.Visible) { lblPostMessageLink.Text = string.Format(@"{2}", Properties.Messages.PostMessage, UrlTools.BuildUrl("Post.aspx?Page=", Tools.UrlEncode(currentPage.FullName)), Properties.Messages.PostMessage); } lblBackLink.Visible = discussMode || viewCodeMode; if(lblBackLink.Visible) { lblBackLink.Text = string.Format(@"{2}", Properties.Messages.Back, UrlTools.BuildUrl(Tools.UrlEncode(currentPage.FullName), Settings.PageExtension, "?NoRedirect=1"), Properties.Messages.Back); } } /// /// Gets the number of backups for the current page. /// /// The number of backups. private int GetBackupCount() { return Pages.GetBackups(currentPage).Count; } /// /// Gets the number of attachments for the current page. /// /// The number of attachments. private int GetAttachmentCount() { int count = 0; foreach(IFilesStorageProviderV30 prov in Collectors.FilesProviderCollector.AllProviders) { count += prov.ListPageAttachments(currentPage).Length; } return count; } /// /// Sets the content and visibility of all labels used in the page. /// private void SetupLabels() { if(discussMode) { lblModified.Visible = false; lblModifiedDateTime.Visible = false; lblBy.Visible = false; lblAuthor.Visible = false; lblCategorizedAs.Visible = false; lblPageCategories.Visible = false; lblNavigationPaths.Visible = false; lblDiscussedPage.Text = "" + FormattingPipeline.PrepareTitle(currentContent.Title, false, FormattingContext.PageContent, currentPage) + ""; } else { lblPageDiscussionFor.Visible = false; lblDiscussedPage.Visible = false; lblModifiedDateTime.Text = Preferences.AlignWithTimezone(currentContent.LastModified).ToString(Settings.DateTimeFormat); lblAuthor.Text = Users.UserLink(currentContent.User); lblPageCategories.Text = GetFormattedPageCategories(); } } /// /// Sets the Print and RSS links. /// private void SetupPrintAndRssLinks() { if(!viewCodeMode) { lblPrintLink.Text = string.Format(@"{2}", UrlTools.BuildUrl("Print.aspx?Page=", Tools.UrlEncode(currentPage.FullName), discussMode ? "&Discuss=1" : ""), Properties.Messages.PrinterFriendlyVersion, Properties.Messages.Print); if(Settings.RssFeedsMode != RssFeedsMode.Disabled) { lblRssLink.Text = string.Format(@"RSS", UrlTools.BuildUrl("RSS.aspx?Page=", Tools.UrlEncode(currentPage.FullName), discussMode ? "&Discuss=1" : ""), discussMode ? Properties.Messages.RssForThisDiscussion : Properties.Messages.RssForThisPage, discussMode ? " class=\"discuss\"" : ""); } else lblRssLink.Visible = false; } else { lblPrintLink.Visible = false; lblRssLink.Visible = false; } } /// /// Gets the categories for the current page, already formatted for display. /// /// The categories, formatted for display. private string GetFormattedPageCategories() { CategoryInfo[] categories = Pages.GetCategoriesForPage(currentPage); if(categories.Length == 0) { return string.Format(@"{2}", GetCategoryLink("-"), Properties.Messages.Uncategorized, Properties.Messages.Uncategorized); } else { StringBuilder sb = new StringBuilder(categories.Length * 10); for(int i = 0; i < categories.Length; i++) { sb.AppendFormat(@"{2}", GetCategoryLink(categories[i].FullName), NameTools.GetLocalName(categories[i].FullName), NameTools.GetLocalName(categories[i].FullName)); if(i != categories.Length - 1) sb.Append(", "); } return sb.ToString(); } } /// /// Gets the link to a category. /// /// The full name of the category. /// The link URL. private string GetCategoryLink(string category) { return UrlTools.BuildUrl("AllPages.aspx?Cat=", Tools.UrlEncode(category)); } /// /// Sets the content of the META description and keywords for the current page. /// private void SetupMetaInformation() { // Set keywords and description if(currentContent.Keywords != null && currentContent.Keywords.Length > 0) { Literal lit = new Literal(); lit.Text = string.Format("", PrintKeywords(currentContent.Keywords)); Page.Header.Controls.Add(lit); } if(!string.IsNullOrEmpty(currentContent.Description)) { Literal lit = new Literal(); lit.Text = string.Format("", currentContent.Description); Page.Header.Controls.Add(lit); } } /// /// Prints the keywords in a CSV list. /// /// /// private string PrintKeywords(string[] keywords) { StringBuilder sb = new StringBuilder(50); for(int i = 0; i < keywords.Length; i++) { sb.Append(keywords[i]); if(i != keywords.Length - 1) sb.Append(", "); } return sb.ToString(); } /// /// Verifies the need for a page redirection, and performs it when appropriate. /// private void VerifyAndPerformPageRedirection() { if(currentPage == null) return; // Force formatting so that the destination can be detected Content.GetFormattedPageContent(currentPage, true); PageInfo dest = Redirections.GetDestination(currentPage); if(dest == null) return; if(dest != null) { if(Request["NoRedirect"] != "1") { UrlTools.Redirect(dest.FullName + Settings.PageExtension + "?From=" + currentPage.FullName, false); } else { // Write redirection hint StringBuilder sb = new StringBuilder(); sb.Append(@"
"); sb.Append(Properties.Messages.ThisPageRedirectsTo); sb.Append(": "); sb.Append(@""); PageContent k = Content.GetPageContent(dest, true); sb.Append(FormattingPipeline.PrepareTitle(k.Title, false, FormattingContext.PageContent, currentPage)); sb.Append("
"); Literal literal = new Literal(); literal.Text = sb.ToString(); plhContent.Controls.Add(literal); } } } /// /// Sets the breadcrumbs trail, if appropriate. /// private void SetupBreadcrumbsTrail() { if(Settings.DisableBreadcrumbsTrail || discussMode || viewCodeMode) { lblBreadcrumbsTrail.Visible = false; return; } StringBuilder sb = new StringBuilder(1000); sb.Append(@"
"); PageInfo[] pageTrail = SessionFacade.Breadcrumbs.AllPages; int min = 3; if(pageTrail.Length < 3) min = pageTrail.Length; sb.Append(@"
"); if(pageTrail.Length > 3) { // Write hyperLink sb.Append(@"("); sb.Append(pageTrail.Length.ToString()); sb.Append(") "); } for(int i = pageTrail.Length - min; i < pageTrail.Length; i++) { AppendBreadcrumb(sb, pageTrail[i], "s"); } sb.Append("
"); sb.Append(@"
"); // Write hyperLink sb.Append(@"[X] "); for(int i = 0; i < pageTrail.Length; i++) { AppendBreadcrumb(sb, pageTrail[i], "f"); } sb.Append("
"); sb.Append("
"); lblBreadcrumbsTrail.Text = sb.ToString(); } /// /// Appends a breadbrumb trail element. /// /// The destination . /// The page to append. /// The drop-down menu ID prefix. private void AppendBreadcrumb(StringBuilder sb, PageInfo page, string dpPrefix) { PageNameComparer comp = new PageNameComparer(); PageContent pc = Content.GetPageContent(page, true); string id = AppendBreadcrumbDropDown(sb, page, dpPrefix); string nspace = NameTools.GetNamespace(page.FullName); sb.Append("» "); if(comp.Compare(page, currentPage) == 0) sb.Append(""); sb.AppendFormat(@"{1}", Tools.UrlEncode(page.FullName) + Settings.PageExtension, FormattingPipeline.PrepareTitle(pc.Title, false, FormattingContext.PageContent, currentPage) + (string.IsNullOrEmpty(nspace) ? "" : (" (" + NameTools.GetNamespace(page.FullName) + ")")), (id != null ? @" onmouseover=""javascript:return __ShowDropDown(event, '" + id + @"', this);""" : ""), (id != null ? @" id=""lnk" + id + @"""" : ""), (id != null ? @" onmouseout=""javascript:return __HideDropDown('" + id + @"');""" : "")); if(comp.Compare(page, currentPage) == 0) sb.Append(""); sb.Append(" "); } /// /// Appends the drop-down menu DIV with outgoing links for a page. /// /// The destination . /// The page. /// The drop-down menu DIV ID prefix. /// The DIV ID, or null if no target pages were found. private string AppendBreadcrumbDropDown(StringBuilder sb, PageInfo page, string dbPrefix) { // Build outgoing links list // Generate list DIV // Return DIV's ID string[] outgoingLinks = Pages.GetPageOutgoingLinks(page); if(outgoingLinks == null || outgoingLinks.Length == 0) return null; string id = dbPrefix + Guid.NewGuid().ToString(); StringBuilder buffer = new StringBuilder(300); buffer.AppendFormat(@"
", id); bool pageAdded = false; foreach(string link in outgoingLinks) { PageInfo target = Pages.FindPage(link); if(target != null) { pageAdded = true; PageContent cont = Content.GetPageContent(target, true); string title = FormattingPipeline.PrepareTitle(cont.Title, false, FormattingContext.PageContent, currentPage); buffer.AppendFormat(@"{2}", link, Settings.PageExtension, title, title); } } buffer.Append("
"); sb.Insert(0, buffer.ToString()); if(pageAdded) return id; else return null; } /// /// Sets the redirection source page link, if appropriate. /// private void SetupRedirectionSource() { if(Request["From"] != null) { PageInfo source = Pages.FindPage(Request["From"]); if(source != null) { StringBuilder sb = new StringBuilder(300); sb.Append(@"
"); sb.Append(Properties.Messages.RedirectedFrom); sb.Append(": "); sb.Append(@""); PageContent w = Content.GetPageContent(source, true); sb.Append(FormattingPipeline.PrepareTitle(w.Title, false, FormattingContext.PageContent, currentPage)); sb.Append("
"); lblRedirectionSource.Text = sb.ToString(); } else lblRedirectionSource.Visible = false; } else lblRedirectionSource.Visible = false; } /// /// Sets the navigation paths label. /// private void SetupNavigationPaths() { string[] paths = NavigationPaths.PathsPerPage(currentPage); string currentPath = Request["NavPath"]; if(!string.IsNullOrEmpty(currentPath)) currentPath = currentPath.ToLowerInvariant(); if(!discussMode && !viewCodeMode && paths.Length > 0) { StringBuilder sb = new StringBuilder(500); sb.Append(Properties.Messages.Paths); sb.Append(": "); for(int i = 0; i < paths.Length; i++) { NavigationPath path = NavigationPaths.Find(paths[i]); if(path != null) { if(currentPath != null && paths[i].ToLowerInvariant().Equals(currentPath)) sb.Append(""); sb.Append(@""); sb.Append(NameTools.GetLocalName(path.FullName)); sb.Append(""); if(currentPath != null && paths[i].ToLowerInvariant().Equals(currentPath)) sb.Append(""); if(i != paths.Length - 1) sb.Append(", "); } } lblNavigationPaths.Text = sb.ToString(); } else lblNavigationPaths.Visible = false; } /// /// Prepares the previous and next pages link for navigation paths. /// /// The previous page link. /// The next page link. private void SetupAdjacentPages() { StringBuilder prev = new StringBuilder(50), next = new StringBuilder(50); if(Request["NavPath"] != null) { NavigationPath path = NavigationPaths.Find(Request["NavPath"]); if(path != null) { int idx = Array.IndexOf(path.Pages, currentPage.FullName); if(idx != -1) { if(idx > 0) { PageInfo prevPage = Pages.FindPage(path.Pages[idx - 1]); prev.Append(@"« "); } if(idx < path.Pages.Length - 1) { PageInfo nextPage = Pages.FindPage(path.Pages[idx + 1]); next.Append(@" »"); } } } } if(prev.Length > 0) { lblPreviousPage.Text = prev.ToString(); } else lblPreviousPage.Visible = false; if(next.Length > 0) { lblNextPage.Text = next.ToString(); } else lblNextPage.Visible = false; } /// /// Sets the JavaScript double-click editing handler. /// private void SetupDoubleClickHandler() { if(Settings.EnableDoubleClickEditing && !discussMode && !viewCodeMode) { StringBuilder sb = new StringBuilder(200); sb.Append(@""); lblDoubleClickHandler.Text = sb.ToString(); } else lblDoubleClickHandler.Visible = false; } /// /// Sets the email notification button. /// private void SetupEmailNotification() { if(SessionFacade.LoginKey != null && SessionFacade.CurrentUsername != "admin") { bool pageChanges; bool discussionMessages; UserInfo user = Users.FindUser(SessionFacade.CurrentUsername); if(user.Provider.UsersDataReadOnly) { btnEmailNotification.Visible = false; return; } Users.GetEmailNotification(user, currentPage, out pageChanges, out discussionMessages); bool active = false; if(discussMode) { active = discussionMessages; } else { active = pageChanges; } if(active) { btnEmailNotification.CssClass = "activenotification" + (discussMode ? " discuss" : ""); btnEmailNotification.ToolTip = Properties.Messages.EmailNotificationsAreActive; } else { btnEmailNotification.CssClass = "inactivenotification" + (discussMode ? " discuss" : ""); btnEmailNotification.ToolTip = Properties.Messages.ClickToEnableEmailNotifications; } } else btnEmailNotification.Visible = false; } protected void btnEmailNotification_Click(object sender, EventArgs e) { bool pageChanges; bool discussionMessages; UserInfo user = Users.FindUser(SessionFacade.CurrentUsername); Users.GetEmailNotification(user, currentPage, out pageChanges, out discussionMessages); if(discussMode) { Users.SetEmailNotification(user, currentPage, pageChanges, !discussionMessages); } else { Users.SetEmailNotification(user, currentPage, !pageChanges, discussionMessages); } SetupEmailNotification(); } /// /// Sets the actual page content, based on the current view mode (normal, discussion, view code). /// /// A value indicating whether the current user can post messages. /// A value indicating whether the current user can manage the discussion. private void SetupPageContent(bool canPostMessages, bool canManageDiscussion) { if(!discussMode && !viewCodeMode) { Literal literal = new Literal(); literal.Text = Content.GetFormattedPageContent(currentPage, true); plhContent.Controls.Add(literal); } else if(!discussMode && viewCodeMode) { if(Settings.EnableViewPageCodeFeature) { Literal literal = new Literal(); StringBuilder sb = new StringBuilder(currentContent.Content.Length + 100); sb.Append(@""); literal.Text = sb.ToString(); plhContent.Controls.Add(literal); } } else if(discussMode && !viewCodeMode) { PageDiscussion discussion = LoadControl("~/PageDiscussion.ascx") as PageDiscussion; discussion.CurrentPage = currentPage; discussion.CanPostMessages = canPostMessages; discussion.CanManageDiscussion = canManageDiscussion; plhContent.Controls.Add(discussion); } } } }