예제 #1
0
 /// <summary>
 /// Checks whether the current user can cancel his/her last modification on the status of the article.
 /// This can only happen if he/she was the last one to perform an update on it.
 /// </summary>
 /// <param name="article">An article.</param>        
 /// <returns>True if the user can undo his last status change.</returns>
 public static bool CanCurrentUserUndoStatus(WikiArticle article)
 {
     return CanUserUndoStatus(article, CurrentUser);
 }
예제 #2
0
 /// <summary>
 /// Checks whether an article has an approved version, i.e. it has a validated copy visible to external users.
 /// </summary>
 /// <param name="article">An article.</param>        
 /// <returns>True if there exists an approved version of the article.</returns>
 public static bool DoesArticleHaveApprovedVersion(WikiArticle article)
 {
     return DoesArticleHaveApprovedVersion(article.Type, article.Title);
 }
예제 #3
0
        /// <summary>
        /// Page load.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Arguments</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                string articleFullTitle = string.Empty;

                if (!Page.IsPostBack)
                {
                    // Title.
                    string urlArticleTitle = Request.QueryString["page"];
                    if (!string.IsNullOrEmpty(urlArticleTitle))
                    {
                        articleFullTitle = Tools.UrlToText(urlArticleTitle);
                        this.hdnArticleFullTitle.Value = articleFullTitle;
                    }
                }
                else
                {
                    articleFullTitle = this.hdnArticleFullTitle.Value;
                }

                // Rights: The user has only external rights => Redirect.
                if (!Authentication.CanCurrentUserSeeInternalContent)
                    if (!string.IsNullOrEmpty(articleFullTitle) && DataModule.DoesArticleHaveApprovedVersion(articleFullTitle))
                        Response.Redirect(Tools.GetUrlToRead(articleFullTitle));
                    else
                        Response.Redirect(Tools.DEFAULT_PAGE);

                if (!string.IsNullOrEmpty(articleFullTitle) && DataModule.DoesArticleExist(articleFullTitle))
                {
                    #region Update
                    Master.PageAction = PageAction.Edit;
                    Master.ArticleTitle = articleFullTitle;
                    this.m_Article = DataModule.GetArticle(articleFullTitle);
                    if (this.m_Article == null)
                        throw new Exception("The article exists but could not be retrieved.");

                    // Are we editing a section?
                    //m_Section = Convert.ToInt32(Request.QueryString["section"]);
                    if (!int.TryParse(Request.QueryString["section"], out m_Section))
                        m_Section = -1;
                    if (!Page.IsPostBack)
                    {
                        if (m_Section > 0)
                            this.tbxArticleText.Text = WikiParser.GetSectionText(this.m_Article.Text, m_Section);
                        else
                            this.tbxArticleText.Text = this.m_Article.Text;
                    }
                    this.lblPageAction.Text = this.Master.PageAction.ToString();
                    this.lblArticleTitle.Text = this.m_Article.TitleWithType;
                    this.tbxArticleTitle.Visible = false;
                    #endregion Update
                }
                else
                {
                    if (!Authentication.CurrentUser.CanCreate)
                        Response.Redirect(Tools.DEFAULT_PAGE);

                    #region Create
                    Master.PageAction = PageAction.Create;
                    Master.ArticleTitle = string.Empty;
                    if (!Page.IsPostBack)
                    {
                        // Extract the title and type from the full title.
                        // Note that these methods give default parameters if needed.
                        string articleTitle = Tools.GetArticleTitle(articleFullTitle);
                        if (articleTitle.Length == 0)
                            articleTitle = DEFAULT_EDITOR_TITLE;
                        ArticleType articleType = Tools.GetArticleType(articleFullTitle);

                        this.lblPageAction.Text = this.Master.PageAction.ToString();
                        this.lblArticleType.Text = articleType.ToString();
                        this.lblArticleTitle.Visible = false;
                        this.tbxArticleTitle.Visible = true;
                        this.tbxArticleTitle.Text = articleTitle;
                        this.tbxArticleText.Text = string.Format(DEFAULT_EDITOR_TEXT_FORMAT, articleTitle);
                    }
                    #endregion Create
                }

                #region Rights
                // Note that if the user has no editing rights, he was redirected above in this method.
                if (this.m_Article == null && Authentication.CurrentUser.CanCreate)
                {
                    // The user can create and is creating the article.
                    this.btnSave.ToolTip = "Save your modifications and go back to the Read page. This does not automatically remove the lock you have on the article.";
                    this.btnCancel.ToolTip = "Cancel your modifications and go back to the Read page. This does not automatically remove the lock you have on the article.";
                    this.cbxUnlock.Text = "Also free the article?";
                    this.cbxUnlock.ToolTip = "Additionally remove yourself as the current editor thus enabling someone else to edit it.";
                    this.btnSave.Visible = true;
                    this.btnCancel.Visible = true;
                    this.cbxUnlock.Visible = true;
                }
                else if (Authentication.CouldCurrentUserValidateArticle(this.m_Article))
                {
                    // The user has editing rights that could allow her to perform some action if the article is not locked yet.
                    if (this.m_Article.IsLocked)
                    {
                        // The article is locked, but by whom?
                        if (this.m_Article.LockedBy == Authentication.CurrentUser.UserLogin)
                        {
                            // The article is locked by the current user.
                            this.btnSave.ToolTip = "Save your modifications and go back to the Read page. This does not automatically remove the lock you have on the article.";
                            this.btnCancel.ToolTip = "Cancel your modifications and go back to the Read page. This does not automatically remove the lock you have on the article.";
                            this.cbxUnlock.Text = "Also free the article?";
                            this.cbxUnlock.ToolTip = "Additionally remove yourself as the current editor thus enabling someone else to edit it.";
                            this.btnSave.Visible = true;
                            this.btnCancel.Visible = true;
                            this.cbxUnlock.Visible = true;
                        }
                        else
                        {
                            // The article is locked by another user.
                            this.lblPageAction.Text = "Source";
                            this.divEditorTop.Visible = false;
                            this.tbxArticleText.ReadOnly = true;
                            User lockedByUser = DataModule.GetInternalUser(this.m_Article.LockedBy);
                            //int nbOfDaysOfLock = Tools.GetNumberOfDaysSinceDate(this.m_Article.LockedAt);
                            this.lblStatusInformation.Text = string.Format("This article is currently being edited by <b>{0}</b>.  Last modification <b>{1}</b>.",
                                lockedByUser.FullName, Tools.GetDateAndTimeText(this.m_Article.LastModificationDate));
                        }
                    }
                    else
                    {
                        // The article is not locked. Offer him/her to lock it.
                        this.lblPageAction.Text = "Source";
                        this.divEditorTop.Visible = false;
                        this.tbxArticleText.ReadOnly = true;
                        //this.lblStatusInformation.Text = "This article is currently readonly";
                        this.btnLock.ToolTip = "Take this article for edit and prevent someone else to modify it.";
                        this.btnLock.Visible = true;
                    }
                }
                else
                {
                    // The user has some editing rights but the article publication process is further ahead than her/his rights allow.
                    // Note that if the user has no editing rights, s/he was redirected at the beginning of this method.
                    this.lblPageAction.Text = "Source";
                    this.divEditorTop.Visible = false;
                    this.tbxArticleText.ReadOnly = true;    //this.tbxArticleText.CssClass += " faded";
                    this.lblStatusInformation.Text = "This article is undergoing its publication process beyond your editing rights.";
                }
                #endregion Rights
            }
            catch (Exception ex)
            {
                string javascriptCall = string.Format(@"displayErrorMessage('lblErrorMessage', '{0}');", Tools.TextToJavascript(ex.Message));
                Page.ClientScript.RegisterStartupScript(this.GetType(), "displayErrorMessage", javascriptCall, true);
            }
        }
예제 #4
0
        /// <summary>
        /// Updates the type of an article.
        /// </summary>
        /// <param name="article"></param>
        /// <param name="articleNewType"></param>
        /// <returns></returns>
        public static bool UpdateArticleType(WikiArticle article, ArticleType articleNewType)
        {
            // Check that the new type is not Code or Site, since article of those types are generated automatically and cannot be set manually.
            if (articleNewType == ArticleType.Code || articleNewType == ArticleType.Site)
                throw new NotSupportedException(string.Format("The title of articles of type {0} cannot be edited.", articleNewType.ToString()));

            // Checks that there is not already an article with the same type in the target new category.
            if (DataModule.DoesIdenticalArticleExist(Tools.GetArticleFullTitle(articleNewType, article.Title), article.Id))
                return false;

            // Refresh the type of the current article.
            article.Type = articleNewType;

            // Update the type of the article in DB.
            string query = string.Format("UPDATE tbl_articles SET art_type = '{0}' WHERE art_id_pkey = {1}", (int)articleNewType, article.Id);
            return Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
        }
예제 #5
0
 /// <summary>
 /// Update the status of an article.
 /// This method is private because it does not perform any user rights checks, which must be thus done before calling it.
 /// </summary>
 /// <param name="article">An article whose status is updated.</param>
 /// <param name="user">The user updating the status of an article.</param>
 /// <param name="articleStatus">The new status of the article.</param>
 /// <param name="mustReleaseLock">Indicates that the lock that user has on the article must be released.</param>
 /// <returns>True if the query was successful.</returns>
 private static bool UpdateArticleStatus(WikiArticle article, User user, ArticleStatus articleStatus, bool mustReleaseLock)
 {
     // No user rights are checked except that the article is not locked by another user.
     // The last modification user is also updated so that we can check whether the user can undo the article afterwards.
     string query = string.Format(@"UPDATE tbl_articles SET art_status = {2}, art_modification_user = '******', art_validation_date = GETDATE(), art_validation_user = '******', art_locked_by = '{3}'
         WHERE art_id_pkey = {0} AND (art_locked_by = '{1}' OR art_locked_by = '')",
         article.Id, user.UserLogin, (int)articleStatus, mustReleaseLock ? string.Empty : user.UserLogin);
     bool isSuccessful = Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
     if (isSuccessful)
     {
         // If the query was successful, update the current article.
         article.Status = articleStatus;
         if (mustReleaseLock)
             article.LockedBy = string.Empty;
         else
             article.LockedBy = user.UserLogin;
     }
     return isSuccessful;
 }
예제 #6
0
        /// <summary>
        /// Set the status of the article to "Written".
        /// </summary>
        /// <param name="article">An article whose status is to be advanced.</param>
        /// <param name="user">The user who is changing the status of the article.</param>
        /// <returns>True if the status of the article was succesfully advanced.</returns>
        public static bool SetArticleToWritten(WikiArticle article, User user)
        {
            if (article.Type == ArticleType.Code || article.Type == ArticleType.Site)
                throw new NotSupportedException(string.Format("This method cannot be used to update an article of type {0}.", article.Type.ToString()));

            if (!Authentication.CanArticleBeCompletedByUser(article, user)) return false;   // Check rights.

            // Release if the user doesn't have the rights to go on with the publication process.
            return UpdateArticleStatus(article, user, ArticleStatus.Written, user.Rights < UserRights.Reviewer);
        }
예제 #7
0
        /// <summary>
        /// Update a database article after having copied its previous version to history (the ID of the article must already exist).
        /// </summary>
        /// <param name="article">A modified article to update in database based on its (already existing) ID.</param>
        /// <param name="user">The acronym of the user that made the update.</param>
        /// <param name="error">A reference parameter filled upon encountering error.</param>
        /// /// <returns>True if the article was correctly updated.</returns>
        public static bool UpdateArticleText(WikiArticle article, User user, ref string error)
        {
            // Check the type of the article.
            if (article.Type == ArticleType.Code || article.Type == ArticleType.Site)
                throw new NotSupportedException(string.Format("This method cannot be used to update an article of type {0}.", article.Type.ToString()));

            // Check user rights.
            if (!Authentication.CanUserValidateArticle(article, user))
            {
                error = "You don't have the right to edit this article.";
                return false;
            }

            // Check that the article exists.
            if (article.Id <= 0 || !DoesArticleExist(article.Id))
            {
                error = "The article does not exist.";
                return false;
            }

            // Copy previous version into history.
            // The following logic limits the number of entries in the history table to one for the same article on the same day by the same user.
            bool isUserLastEditor = article.LastModificationUser == user.UserLogin;
            bool hasDayPassed = Tools.GetNumberOfDaysSinceDate(article.LastModificationDate) >= 1;
            if (!isUserLastEditor || hasDayPassed)
            {
                string copyToHistoryQuery = string.Format(@"INSERT INTO tbl_article_history
                    (ahi_art_id_fkey, ahi_title, ahi_text, ahi_history_date, ahi_history_user)
                    SELECT art_id_pkey, art_title, art_text, GETDATE(), '{1}' FROM tbl_articles WHERE art_id_pkey = {0}",
                    article.Id, user.UserLogin);
                DataAccess.ExecuteOwnStatement(copyToHistoryQuery);
            }

            // Limit the size of the summary to its maximal length.
            string articleSummary = WikiParser.GetSummary(article.Text);
            if (articleSummary.Length > Tools.SUMMARY_MAX_LENGTH)
                articleSummary = articleSummary.Remove(Tools.SUMMARY_MAX_LENGTH);

            // Updates the summary in the current Article.
            article.Summary = articleSummary;

            // Update the text, summary and modification information of the article.
            string query = string.Format(@"UPDATE tbl_articles SET art_text = '{1}', art_summary = '{2}', art_modification_date = GETDATE(), art_modification_user = '******' WHERE art_id_pkey = {0}",
                article.Id, Tools.TextToSQL(article.Text), Tools.TextToSQL(articleSummary), user.UserLogin);
            return Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
        }
예제 #8
0
 /// <summary>
 /// Checks whether the current user could set the status of a given article as "Reviewed" if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>        
 /// <returns>True if the current user could review the article if he/she had a lock on it.</returns>
 public static bool CouldCurrentUserReviewArticle(WikiArticle article)
 {
     return CouldUserReviewArticle(article, CurrentUser);
 }
예제 #9
0
 /// <summary>
 /// Checks whether a user could set the status of a given article to "Approved" if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user could approve the article if he/she had locked it.</returns>
 public static bool CouldUserApproveArticle(WikiArticle article, User user)
 {
     return user.Rights >= UserRights.Approver && article.Status == ArticleStatus.Reviewed;
 }
예제 #10
0
 /// <summary>
 /// Checks whether the current user could set the status of a given article as "Approved" if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>        
 /// <returns>True if the current user could approve the article if he/she had locked it.</returns>
 public static bool CouldCurrentUserApproveArticle(WikiArticle article)
 {
     return CouldUserApproveArticle(article, CurrentUser);
 }
예제 #11
0
 /// <summary>
 /// Checks whether the current user could set the status of a given article as "Written" if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>        
 /// <returns>True if the current user could complete the article if he/she had a lock on it.</returns>
 public static bool CouldCurrentUserCompleteArticle(WikiArticle article)
 {
     return CouldUserCompleteArticle(article, CurrentUser);
 }
예제 #12
0
 /// <summary>
 /// Checks whether a user can perform any editing or validating action on a given article.
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user can perform any action on the article.</returns>
 public static bool CanUserValidateArticle(WikiArticle article, User user)
 {
     return article.LockedBy == user.UserLogin && CouldUserValidateArticle(article, user);
 }
예제 #13
0
 /// <summary>
 /// Checks whether the user can cancel his/her last modification on the status of the article.
 /// This can only happen if he/she was the last one to perform an update on it.
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user can undo his last status change.</returns>
 public static bool CanUserUndoStatus(WikiArticle article, User user)
 {
     // The user musth ave editing rights, i.e. must be a writer or above.
     bool isUserEditor = user.Rights >= UserRights.Writer;
     // "Draft" articles cannot have their status reverted since they are the first status a public article can have.
     bool canArticleBeUndone = article.Status > ArticleStatus.Draft;
     // The user must be the last validator of the article.
     bool isUserLastValidator = article.ValidationUser == user.UserLogin;
     // We also check that the user was the last modifier, since he/she's not supposed to revert the status if someone else has made changes since.
     bool isUserLastModifier = article.LastModificationUser == user.UserLogin;
     // The article is not currently locked by someone else.
     bool isArticleLockedByAnotherUser = article.IsLocked && article.LockedBy != user.UserLogin;
     return isUserEditor && canArticleBeUndone && isUserLastModifier && isUserLastValidator && !isArticleLockedByAnotherUser;
 }
예제 #14
0
 /// <summary>
 /// Checks whether the current user can perform any editing or validating action on a given article.
 /// </summary>
 /// <param name="article">An article.</param>        
 /// <returns>True if the user can perform any action on the article.</returns>
 public static bool CanCurrentUserValidateArticle(WikiArticle article)
 {
     return article.LockedBy == CurrentUser.UserLogin && CouldUserValidateArticle(article, CurrentUser);
 }
예제 #15
0
 /// <summary>
 /// Updates the publicity of an articles (whether its Internal or Public).
 /// The publicity of an article is implemented by its status.
 /// Publicity == Internal ==> Status == Internal.
 /// Publicity == Public ==> Status >= ToBeWritten.
 /// </summary>
 /// <param name="article">An article whose publicity is updated.</param>
 /// <param name="user">The user that is switching the publicity of the article.</param>
 /// <param name="mustSetToPublic">True if the article publicity must be set to Public, False if the publicity must be set to Internal.</param>
 /// <returns>True if the publicity of the article was successfully updated.</returns>
 public static bool SetArticlePublicity(WikiArticle article, User user, bool mustSetToPublic)
 {
     return mustSetToPublic ? SetArticlePublic(article, user) : SetArticleInternal(article, user);
 }
예제 #16
0
 /// <summary>
 /// Checks whether a user could set the status of a given article to "Written" if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user could complete the article if he/she had a lock on it.</returns>
 public static bool CouldUserCompleteArticle(WikiArticle article, User user)
 {
     return user.Rights >= UserRights.Writer && article.Status == ArticleStatus.Draft;
 }
예제 #17
0
        /// <summary>
        /// Undo the last change of status of the article.
        /// </summary>
        /// <param name="article">An article whose status is to be advanced.</param>
        /// <param name="user">The user who is changing the status of the article.</param>
        /// <returns>True if the status of the article was succesfully undoed.</returns>
        public static bool SetArticleStatusUndo(WikiArticle article, User user)
        {
            if (article.Type == ArticleType.Code || article.Type == ArticleType.Site)
                throw new NotSupportedException(string.Format("This method cannot be used to update an article of type {0}.", article.Type.ToString()));

            if (!Authentication.CanUserUndoStatus(article, user) || article.Status <= ArticleStatus.Draft) return false;   // Check rights.

            return UpdateArticleStatus(article, user, article.Status - 1, false);
        }
예제 #18
0
 /// <summary>
 /// Checks whether a user could set the status of a given article to "Reviewed" if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user could review the article if he/she had a lock on it.</returns>
 public static bool CouldUserReviewArticle(WikiArticle article, User user)
 {
     return user.Rights >= UserRights.Reviewer && article.Status == ArticleStatus.Written;
 }
예제 #19
0
 /// <summary>
 /// Remove any current lock on a given article.
 /// </summary>
 /// <param name="article">An article to unlock.</param>
 /// <returns>True if the article was correctly unlocked.</returns>
 public static bool UnlockArticle(WikiArticle article)
 {
     string query = string.Format(@"UPDATE tbl_articles SET art_locked_by = '' WHERE art_id_pkey = {0} AND art_locked_by <> ' '", article.Id);
     bool isSuccessful = Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
     if (isSuccessful) article.LockedBy = string.Empty;    // If the query was successful, update the current article.
     return isSuccessful;
 }
예제 #20
0
 /// <summary>
 /// Checks whether a user could perform any editing or validating action on a given article if he/she had a lock on it.
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user could perform any action on the article if he/she had locked it.</returns>
 public static bool CouldUserValidateArticle(WikiArticle article, User user)
 {
     return (article.IsInternal && user.Rights >= UserRights.Writer) ||
         CouldUserCompleteArticle(article, user) ||
         CouldUserReviewArticle(article, user) ||
         CouldUserApproveArticle(article, user);
 }
예제 #21
0
 /// <summary>
 /// Updates the title of an existing article.
 /// </summary>
 /// <param name="article">An article to update.</param>
 /// <param name="articleNewTitle">The new title of the article.</param>
 /// <returns>True if the title of the article could be changed. False if the title conflicted with another article.</returns>
 public static bool UpdateArticleTitle(WikiArticle article, string articleNewTitle)
 {
     string query = string.Format(@"UPDATE tbl_articles SET art_title = '{0}' WHERE art_id_pkey = {1}", Tools.TextToSQL(articleNewTitle), article.Id);
     return Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
 }
예제 #22
0
        /// <summary>
        /// Approve the article. This produces an approved read-only copy of the article and set the status of its latest running version to internal.
        /// </summary>
        /// <param name="article">An article whose status is to be advanced.</param>
        /// <param name="user">The user who is changing the status of the article.</param>
        /// <param name="error">A string that can be used to feed information back to the caller.</param>
        /// <returns>True if the status of the article was succesfully advanced.</returns>
        public static bool ApproveArticle(WikiArticle article, User user, ref string error)
        {
            // Check article Type.
            if (article.Type == ArticleType.Code || article.Type == ArticleType.Site)
                throw new NotSupportedException(string.Format("This method cannot be used to update an article of type {0}.", article.Type.ToString()));

            // Check the the article exists in DB.
            if (article.Id <= 0 || !DoesArticleExist(article.Id))
            {
                error = "The article does not exist";
                return false;
            }

            // Check that the user can approve the article right now.
            if (!Authentication.CanArticleBeApprovedByUser(article, user))
            {
                error = "You cannot approve this article now, either because you haven't locked the article or you lack the rights to.";
                return false;
            }

            // Save an approved copy of the article.
            // The content of the article can still be modified, but its approved copies will remain unchanged.
            string query = string.Format(@"INSERT INTO tbl_article_approved (app_art_id_fkey, app_title, app_type, app_text, app_summary, app_approval_date, app_approval_user)
                SELECT art_id_pkey, art_title, art_type, art_text, art_summary, GETDATE(), '{1}' FROM tbl_articles WHERE art_id_pkey = {0}",
                article.Id, user.UserLogin);
            bool isSuccessful = Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));

            // Update the status of the article to internal so it gets out of the validation process and can still be edited.
            isSuccessful = isSuccessful && UpdateArticleStatus(article, user, ArticleStatus.Internal, true);

            return isSuccessful;
        }
예제 #23
0
        /// <summary>
        /// Updates the parent categories of an article. The previous parent categories are entirely replaced with the ones provided.
        /// </summary>
        /// <param name="article">An article to update.</param>
        /// <param name="newCategories">The list of update categories of the given article.</param>
        /// <returns>True if the query was successful.</returns>
        public static bool UpdateParentCategories(WikiArticle article, List<WikiArticleInfo> newCategories)
        {
            string query = string.Empty;

            if (newCategories == null)
                return false;

            // If there are no categories in the collection, we can delete every link with this article and return.
            if (newCategories.Count == 0)
            {
                query = string.Format("DELETE FROM tbl_article_hierarchy WHERE ahe_child_art_fkey = {0}", article.Id);
                return Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
            }

            // If the article is a Category, check that it's not already included somewhere in its parent hierarchy.
            // You can't make a Category a child of itself or of other categories having the Category as a parent because it would cause loops in the hiearchy.
            if (article.Type == ArticleType.Category && IsCategoryInCategoriesHierarchy(article, newCategories))
                return false;

            string updatedCategoryIds = string.Empty;
            foreach (WikiArticleInfo category in newCategories)
            {
                // If the link between the article and the category does not exist yet, create it.
                if (!IsArticleInCategory(article.Id, category.Id))
                {
                    query = string.Format("INSERT INTO tbl_article_hierarchy (ahe_child_art_fkey, ahe_parent_art_fkey) VALUES ({0}, {1})",
                        article.Id, category.Id);
                    DataAccess.ExecuteOwnStatement(query);
                }

                // At the same time, keep track of the category indexes => in the end all the categories but those will be deleted.
                updatedCategoryIds += category.Id + ",";
            }
            updatedCategoryIds = updatedCategoryIds.Remove(updatedCategoryIds.Length - 1); // Remove trailing comma.

            // Remove every category link that was not in the categories to save.
            query = string.Format("DELETE FROM tbl_article_hierarchy WHERE ahe_child_art_fkey = {0} AND ahe_parent_art_fkey NOT IN ({1})",
                article.Id, updatedCategoryIds);
            return DataAccess.ExecuteOwnStatement(query) >= 0;  // There might be nothing to delete (nothing unchecked in the GUI).
        }
예제 #24
0
        /// <summary>
        /// Lock the article for the user.
        /// </summary>
        /// <param name="article">An article to lock.</param>
        /// <param name="user">The user that locks the article.</param>
        /// <returns>True if a lock was successfully applied on the article for the user.</returns>
        public static bool LockArticle(WikiArticle article, User user)
        {
            if (!Authentication.CouldUserValidateArticle(article, user)) return false;   // Check rights.

            string query = string.Format(@"UPDATE tbl_articles SET art_locked_by = '{1}' WHERE art_id_pkey = {0} AND art_locked_by = ' '", article.Id, user.UserLogin);
            bool isSuccessful = Convert.ToBoolean(DataAccess.ExecuteOwnStatement(query));
            if (isSuccessful) article.LockedBy = user.UserLogin;   // If the query was successful, update the current article.
            return isSuccessful;
        }
예제 #25
0
        /// <summary>
        /// Deletes every occurence of the article and its relations in database.
        /// </summary>
        /// <param name="article">An article to delete.</param>
        /// <returns>True if every step of the deletion was successful.</returns>
        public static bool DeleteArticle(WikiArticle article)
        {
            // [KDE]: Such a method is too powerful. Only use locally for debugging purposes.
            #if DEBUG
            // Delete the article hiearchy.
            string query = string.Format("DELETE FROM tbl_article_hierarchy WHERE ahe_child_art_fkey = {0} OR ahe_parent_art_fkey = {0}", article.Id);
            DataAccess.ExecuteOwnStatement(query);

            // Delete the article history.
            query = string.Format("DELETE FROM tbl_article_history WHERE ahi_art_id_fkey = {0}", article.Id);
            DataAccess.ExecuteOwnStatement(query);

            // Delete the article approved history.
            query = string.Format("DELETE FROM tbl_article_approved WHERE app_art_id_fkey = {0}", article.Id);
            DataAccess.ExecuteOwnStatement(query);

            // Delete the article
            query = string.Format("DELETE FROM tbl_articles WHERE art_id_pkey = {0}", article.Id);
            return DataAccess.ExecuteOwnStatement(query) > 0;
            #else
            return false;
            #endif
        }
예제 #26
0
        /// <summary>
        /// Set an article Internal. This is achieved by setting its status to "Internal".
        /// </summary>
        /// <param name="article">An article.</param>
        /// <param name="user">The user updating the status of the article.</param>
        /// <returns>True if the status of the article was successfully updated.</returns>
        public static bool SetArticleInternal(WikiArticle article, User user)
        {
            if (article.Status == ArticleStatus.Internal)
                return true;

            if (user.CanCreate && Authentication.CanUserValidateArticle(article, user))
                return UpdateArticleStatus(article, user, ArticleStatus.Internal, false);
            else
                return false;
        }
예제 #27
0
        /// <summary>
        /// Page load.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Arguments.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            // Get the title of the article.
            string articleFullTitle = string.IsNullOrEmpty(Request.QueryString["page"]) ? string.Empty : Tools.UrlToText(Request.QueryString["page"]);

            // Get the version of the article that must be be shown.
            string articleVersionText = Request.QueryString["version"];
            RequestedArticleVersion articleVersion = Authentication.CanCurrentUserSeeInternalContent ?
                Tools.ParseArticleVersion(articleVersionText) : RequestedArticleVersion.Approved;   // Public can only see approved.
            bool mustUseApprovedVersion = articleVersion == RequestedArticleVersion.Approved || articleVersion == RequestedArticleVersion.ApprovedByLatest;

            #region Get Article
            if (articleFullTitle.Length == 0)
            {
                Response.Redirect(Tools.DEFAULT_PAGE);
            }
            else if (articleFullTitle == Tools.RANDOM_PAGE_KEYWORD)
            {
                #region Random
                this.m_Article = DataModule.GetRandomArticle();

                // Redirect the user to a random article page.
                // We can't simply load a random article into the interface because the title of the article would be "random"
                // and the menu links would not work properly.
                if (this.m_Article == null)
                    Response.Redirect(Tools.DEFAULT_PAGE);
                else
                    Response.Redirect("./Read.aspx?page=" + Tools.TextToUrl(this.m_Article.FullTitle));
                #endregion Random
            }
            else if (articleFullTitle == Tools.LATEST_PAGE_KEYWORD)
            {
                #region Latest
                this.m_Article = DataModule.GetLatestArticle();

                // Redirect the user to the read page of the latest modified article.
                // We can't simply load the latest article into the interface because the title of the article would be "latest"
                // and the menu links would not work properly.
                if (this.m_Article == null)
                    Response.Redirect(Tools.DEFAULT_PAGE);
                else
                    Response.Redirect("./Read.aspx?page=" + Tools.TextToUrl(this.m_Article.FullTitle));
                #endregion Latest
            }
            else if (Tools.GetArticleType(articleFullTitle) == ArticleType.Code)
            {
                #region Code
                LoadCodeArticle(Tools.GetArticleTitle(articleFullTitle));
                return;
                #endregion Code
            }
            else if (Tools.GetArticleType(articleFullTitle) == ArticleType.Site)
            {
                #region Site
                LoadSiteArticle(Tools.GetArticleTitle(articleFullTitle));
                return;
                #endregion Site
            }
            else if (DataModule.DoesArticleExist(articleFullTitle))
            {
                #region Wiki Article
                // Should we get the latest version or approved version of the article? And if so, by the title of the article or the title of its approved version?
                bool doesApprovedVersionExist = (articleVersion == RequestedArticleVersion.Approved || articleVersion == RequestedArticleVersion.LatestByApproved) ?
                    DataModule.DoesApprovedArticleExist(articleFullTitle) : DataModule.DoesArticleHaveApprovedVersion(articleFullTitle);

                if (!Authentication.CanCurrentUserSeeInternalContent)
                {
                    if (doesApprovedVersionExist)
                        this.m_Article = DataModule.GetApprovedArticle(articleFullTitle);   // External can only see approved content.
                    else
                        Response.Redirect(Tools.DEFAULT_PAGE);  // No approved version => nothing to display.
                }
                else if (mustUseApprovedVersion && doesApprovedVersionExist)
                {
                    if (articleVersion == RequestedArticleVersion.Approved)
                        this.m_Article = DataModule.GetApprovedArticle(articleFullTitle);
                    else
                        this.m_Article = DataModule.GetApprovedArticleByLatest(articleFullTitle);
                }
                else if (articleVersion == RequestedArticleVersion.LatestByApproved)
                    this.m_Article = DataModule.GetArticleByApproved(articleFullTitle);
                else
                    this.m_Article = DataModule.GetArticle(articleFullTitle);   // Latest version OR no Approved version existed for the given title.
                #endregion Wiki Article
            }
            #endregion Get Article

            #region Missing Article
            if (this.m_Article == null)
            {
                // No article matching the title was found.
                if (Authentication.CanCurrentUserSeeInternalContent && Authentication.CurrentUser.CanCreate)
                {
                    // Offer to the user the possibility to create one.
                    articleFullTitle = Tools.GetArticleFullTitle(articleFullTitle); // Makes sure the type exists and changes it to default if it does not.
                    this.lblArticleTitle.Text = string.Format(@"Create ""{0}""?", articleFullTitle);
                    this.lblArticleContent.Text = string.Format(@"<p>The page you are trying to read does not exist. Would you like to create a new page ""{0}""?</p>",
                        Tools.GetLinkToCreate(articleFullTitle));
                }
                else
                {
                    // Feedback and next action.
                    ArticleType articleType = Tools.GetArticleType(articleFullTitle);
                    articleFullTitle = Tools.GetArticleTitle(articleFullTitle);
                    this.lblArticleTitle.Text = string.Format(@"{0} ""{1}"" does not exist.", articleType, articleFullTitle);
                    this.lblArticleContent.Text = string.Format("<p>The page you are trying to read does not exist.</p>");
                }
                this.lblArticleContent.Text += string.Format("<p>Go back to the {0}.</p>", Tools.GetLinkToUrl("./Home.aspx", "Home page"));
                this.lblArticleContent.Text += string.Format("<p>Go back to the {0}.</p>", Tools.GetLinkToUrl("./Index.aspx", "Index"));
                this.loaParentCategories.Visible = false;
                this.frmStatus.Visible = false;

                // Remove "Export" link in Master page.
                Master.PageAction = PageAction.Read404;
                Master.ArticleTitle = articleFullTitle;
                return;
            }
            #endregion Missing Article

            // Home page to be treated by Home.aspx.
            if(this.m_Article.Type == ArticleType.Homepage)
                Response.Redirect(Tools.GetUrlToHome());

            // Master Page.
            if (this.m_Article.Status == ArticleStatus.Approved)
                Master.PageAction = PageAction.ReadApproved;
            else
                Master.PageAction = PageAction.Read;
            Master.ArticleTitle = this.m_Article == null ? articleFullTitle : this.m_Article.FullTitle;
            Master.PageTitle = this.m_Article == null ? articleFullTitle : this.m_Article.TitleWithType;

            #region Title
            // Set the main (h1) title that is displayed at the top of the page using the type and title of the article.
            // A link to see the approved or normal version of the article may also be provided whereas that applies.
            string articleTypeHtml = this.m_Article.Type == Tools.DEFAULT_ARTICLE_TYPE ? string.Empty : string.Format(@" <span class=""faded"">({0})</span>", this.m_Article.Type.ToString());
            string articleTitleHtml = string.Format(@"{0}{1}", this.m_Article.Title, articleTypeHtml);
            this.lblArticleTitle.Text = articleTitleHtml;// +Environment.NewLine;
            if (Authentication.CurrentUser.Rights >= UserRights.Reader)
            {
                // If the user is an internal user, he can access both versions of the article (normal and approved).
                // External user can only access the approved version (if any).
                if (this.m_Article.Status == ArticleStatus.Approved)
                {
                    string linkToLatestVersion = Tools.GetLinkToRead(this.m_Article.FullTitle, "Link to latest version", RequestedArticleVersion.LatestByApproved);
                    string linkToLatestVersionSpan = string.Format(@"<span class=""title_link"">{0}</span>", linkToLatestVersion);
                    this.lblArticleTitle.Text += linkToLatestVersionSpan;
                }
                else if (DataModule.DoesArticleHaveApprovedVersion(this.m_Article))
                {
                    string linkToApprovedVersion = Tools.GetLinkToRead(this.m_Article.FullTitle, "Link to approved version", RequestedArticleVersion.ApprovedByLatest);
                    string linkToApprovedVersionSpan = string.Format(@"<span class=""title_link"">{0}</span>", linkToApprovedVersion);
                    this.lblArticleTitle.Text += linkToApprovedVersionSpan;
                }
            }
            #endregion Title

            #region Content
            // Check if the current user has the priviledge to edit the article right now - if he had locked it.
            // Setting the article title to empty in the wiki parser will prevent the display of an "[Edit]" link for each section.
            if (Authentication.CouldCurrentUserValidateArticle(this.m_Article))
                this.lblArticleContent.Text = WikiParser.Parse(this.m_Article.Text, this.m_Article.FullTitle, true, Request.Url.Host, Request.ApplicationPath);
            else
                this.lblArticleContent.Text = WikiParser.Parse(this.m_Article.Text, string.Empty, true, Request.Url.Host, Request.ApplicationPath);
            #endregion Content

            #region Category Children
            if (this.m_Article.Type == ArticleType.Category)
            {
                // Child articles & categories.
                if (this.m_Article.Children != null)
                {
                    List<WikiArticleInfo> childPages = mustUseApprovedVersion ? this.m_Article.ApprovedChildren : this.m_Article.Children;
                    this.coaChildPages.Title = string.Format(@"Pages in category {0}", this.m_Article.Title);
                    this.coaChildPages.SubTitle = string.Format("The following {0} in this category.",
                        childPages.Count > 1 ? childPages.Count.ToString() + " pages are" : "page is");
                    this.coaChildPages.WikiArticles = childPages;
                    this.coaChildPages.MustShowType = true;
                    this.coaChildPages.MustShowCheckboxes = false;
                    this.coaChildPages.MustUseApprovedVersion = mustUseApprovedVersion;
                }
            }
            #endregion Category Children

            #region Parent Categories
            List<WikiArticleInfo> parentCategories = mustUseApprovedVersion ? this.m_Article.ParentApprovedCategories : this.m_Article.ParentCategories;
            if (parentCategories != null)
            {
                int nbOfCategories = this.m_Article.ParentCategories.Count;
                if (Authentication.CanCurrentUserSeeInternalContent)
                    if (mustUseApprovedVersion)
                        this.loaParentCategories.Title = "Approved Categories";
                    else
                        this.loaParentCategories.Title = Tools.GetLinkToProperties(this.m_Article.FullTitle + "#Categories", "Categories");
                else
                    this.loaParentCategories.Title = "Categories";
                this.loaParentCategories.SubTitle = "The categories to which this page belongs.";
                this.loaParentCategories.WikiArticles = parentCategories;
                if (mustUseApprovedVersion)
                    this.loaParentCategories.MustUseApprovedVersion = true;
            }
            else
                this.loaParentCategories.Visible = false;

            #endregion Parent Categories

            #region Status
            if (Authentication.CanCurrentUserSeeInternalContent)// && this.m_Article.Status != ArticleStatus.Approved)
            {
                switch (this.m_Article.Status)
                {
                    case ArticleStatus.Internal: this.imgStatus.ImageUrl = "../Images/Icons/key.png"; break;
                    case ArticleStatus.Approved: this.imgStatus.ImageUrl = "../Images/Icons/accept.png"; break;
                    default: this.imgStatus.ImageUrl = "../Images/Icons/page_edit.png"; break;  // page_go.png
                }
                this.imgStatus.ToolTip = this.m_Article.StatusDescription;
                this.lblStatus.Text = this.m_Article.StatusText;
                this.lblStatus.ToolTip = this.m_Article.StatusDescription;

                if (Authentication.CurrentUser.Rights == UserRights.Reader)
                    this.lblStatusDescription.Text = this.m_Article.StatusDescription + ".";
                else if (Authentication.CurrentUser.Rights >= UserRights.Writer && this.m_Article.Status != ArticleStatus.Approved)
                {
                    #region Writer
                    // The user is a writer or above. He/she can see locking information and possibly advance the status of the article.
                    if (Authentication.CouldCurrentUserValidateArticle(this.m_Article))
                    {
                        this.lblSeparator.Visible = true;
                        this.imgLock.Visible = true;

                        // The user has the appropriate rights to validate the article. But it could be locked by someone else!
                        if (this.m_Article.IsLocked && this.m_Article.LockedBy == Authentication.CurrentUser.UserLogin)
                        {
                            // The user has locked the article and can perform some editing action on it.
                            this.imgLock.ImageUrl = "../Images/Icons/lock_edit.png";
                            this.lblLockDescription.Text = "You are the current editor of this article.";
                            this.btnUnlock.ToolTip = "Release the article to allow someone else to work on it.";
                            this.btnUnlock.Visible = true;

                            if (this.m_Article.IsPublic)
                            {
                                if (Authentication.CouldCurrentUserCompleteArticle(this.m_Article))
                                {
                                    this.btnWritten.ToolTip = "Mark this article as completely written and send it for review.";
                                    this.btnWritten.Visible = true;
                                }
                                if (Authentication.CouldCurrentUserReviewArticle(this.m_Article))
                                {
                                    this.btnReviewed.ToolTip = "Mark this article as reviewed and send it for approval.";
                                    this.btnReviewed.Visible = true;
                                }
                                if (Authentication.CouldCurrentUserApproveArticle(this.m_Article))
                                {
                                    this.btnApproved.ToolTip = "Approve the article for public usage. Caution: this will enables public users to read the article.";
                                    this.btnApproved.Visible = true;
                                }
                            }
                        }
                        else if (this.m_Article.IsLocked && this.m_Article.LockedBy != Authentication.CurrentUser.UserLogin)
                        {
                            // The user COULD lock the article IF it was not locked by someone else.
                            this.imgLock.ImageUrl = "../Images/Icons/lock_delete.png";
                            this.imgLock.ToolTip = "This article is being locked by someone else";
                            User currentEditor = DataModule.GetInternalUser(this.m_Article.LockedBy);
                            this.lblLockDescription.Text = string.Format("This article is currently being edited by {0}.", currentEditor.FullName);
                        }
                        else
                        {
                            // The user CAN lock the article AS it is not locked.
                            this.imgLock.ImageUrl = "../Images/Icons/lock_open.png";
                            this.lblLockDescription.Text = "You may take this article for exclusive edition.";
                            this.btnLock.ToolTip = "Take this article for edit and prevent someone else to modify it.";
                            this.btnLock.Visible = true;
                        }
                    }
                    else
                    {
                        // The user cannot do anything because he/she doesn't have the rights to perform any edit at this point.
                        this.imgStatus.ImageUrl = "../Images/Icons/page_delete.png";
                        this.lblStatusDescription.Text = "This article is going on its validation process beyond your rights.";
                    }

                    if (Authentication.CanCurrentUserUndoStatus(this.m_Article))
                    {
                        // The user was the last one to perform an action. He/she may thus cancel his/her last validation action.
                        this.lblLockDescription.Text = " You may cancel your last status change.";
                        this.btnUndo.ToolTip = "Cancel your last change to the status of this article. You may only do this as long as it is not locked or modified by someone else.";
                        this.btnUndo.Visible = true;
                    }
                    #endregion Writer
                }
            }
            else
            {
                // The user is an external user. Don't display any information about the status of articles to public.
                frmStatus.Visible = false;  // Hides the whole form.
            }
            #endregion Status

            #region Footer
            // The footer is located below the article frame.
            // Display the time and user of last modification (only to internal users).
            if (Authentication.CanCurrentUserSeeInternalContent && this.m_Article.Status != ArticleStatus.Approved)
            {
                User lastModificationUser = DataModule.GetInternalUser(this.m_Article.LastModificationUser);
                this.lblPageFooter.Text = string.Format(@"Last modified {0} by <i>{1}</i>",
                    Tools.GetDateAndTimeText(this.m_Article.LastModificationDate), lastModificationUser.FullName);
            }
            // [KDE]: Debug info.
            //if (Authentication.CurrentUser.UserName == "KDE")
            //{
            //    lblPageFooter.Text += string.Format("{0}Host = {1}{0}ApplicationPath = {2}{0}", "<br />", Request.Url.Host, Request.ApplicationPath);
            //}
            #endregion Footer
        }
예제 #28
0
 /// <summary>
 /// Set an article Public. This is achieved by moving its status from "Internal" to "ToBeWritten".
 /// </summary>
 /// <param name="article">An article to set Public.</param>
 /// <param name="user">The user updating the status of the article.</param>
 /// <returns>True if the status of the article was successfully updated.</returns>
 public static bool SetArticlePublic(WikiArticle article, User user)
 {
     // An article can only be set to "Public" from the "Internal" status.
     if (article.Status == ArticleStatus.Internal && user.CanCreate && Authentication.CanUserValidateArticle(article, user))
         return UpdateArticleStatus(article, user, ArticleStatus.Draft, false);
     else
         return false;
 }
예제 #29
0
        /// <summary>
        /// Handles a click on the Save button.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Arguments.</param>
        protected void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                string articleFullTitle = this.hdnArticleFullTitle.Value;
                string articleText = this.tbxArticleText.Text;
                string error = string.Empty;

                // Check the HTML syntax.
                //HtmlParser.CheckHtml(newText, out error);
                //if (!string.IsNullOrEmpty(error))
                //    throw new Exception("The article cannot be saved because the html code isn't well formed: " + error);

                if (Master.PageAction == PageAction.Create)
                {
                    #region Create
                    string articleNewTitle = this.tbxArticleTitle.Text.Trim();

                    // Check that the article title provided is not empty (or left to default).
                    if (string.IsNullOrEmpty(articleNewTitle) || articleNewTitle == DEFAULT_EDITOR_TITLE)
                        throw new Exception("Please set the title of the article before saving.");

                    // Punish the user for trying to enter an invalid title.
                    if (articleNewTitle.Contains(":"))
                        throw new Exception("Colon (:) is not a valid character within an article title.");

                    ArticleType articleType = Tools.GetArticleType(articleFullTitle);   // The type of the article is indicated by the prefix in the title (e.g. "Category:").
                    articleFullTitle = Tools.GetArticleFullTitle(articleType, articleNewTitle);
                    WikiArticle newArticle = DataModule.CreateArticle(articleNewTitle, articleType, articleText, Authentication.CurrentUser, ref error);
                    if (ReferenceEquals(newArticle, null))
                        throw new Exception("The article could not be created: " + error);
                    else
                        this.m_Article = newArticle;
                    #endregion Create
                }
                else
                {
                    #region Update
                    // Article or article section?
                    if (this.m_Section < 0)
                        this.m_Article.Text = articleText;
                    else
                        this.m_Article.Text = WikiParser.GetTextWithReinsertedSectionText(this.m_Article.Text, this.m_Section, articleText);

                    // Update the article.
                    if (!DataModule.UpdateArticleText(this.m_Article, Authentication.CurrentUser, ref error))
                        throw new Exception("The article could not be updated: " + error);
                    #endregion Update
                }

                // Unlock the article if necessary.
                if (this.cbxUnlock.Checked)
                    DataModule.UnlockArticle(this.m_Article);

                // The page is now saved.
                // Redirect either to the Read or Home page, if possible to the specific section from which the user comes from.
                if (Tools.GetArticleType(articleFullTitle) == ArticleType.Homepage)
                    Response.Redirect(Tools.GetUrlToHome(this.m_Section));
                else
                    Response.Redirect(Tools.GetUrlToRead(articleFullTitle, this.m_Section));

            }
            catch (Exception ex)
            {
                string javascriptCall = string.Format(@"displayErrorMessage('lblErrorMessage', '{0}');", Tools.TextToJavascript(ex.Message));
                Page.ClientScript.RegisterStartupScript(this.GetType(), "displayErrorMessage", javascriptCall, true);
            }
        }
예제 #30
0
 /// <summary>
 /// Checks whether a user can set the status of a given article to "Reviewed".
 /// </summary>
 /// <param name="article">An article.</param>
 /// <param name="user">A user.</param>
 /// <returns>True if the user can review the article.</returns>
 public static bool CanArticleBeReviewedByUser(WikiArticle article, User user)
 {
     return CouldUserReviewArticle(article, user) && article.LockedBy == user.UserLogin;
 }