Exemple #1
0
 public static void pageArticles_Images_Upload(ref StringBuilder content, string pluginid, Connector conn, ref Misc.PageElements pageElements, HttpRequest request, HttpResponse response, bool permCreate)
 {
     // Upload an image
     // -- Ensure the user has creation permissions, else we'll 404
     if (!permCreate) return;
     string error = null;
     HttpPostedFile image = request.Files["image"];
     string title = request.Form["title"];
     string captcha = request.Form["captcha"];
     // Check for postback
     if (title != null && captcha != null && image != null)
     {
         // Validate
         if (!Common.Validation.validCaptcha(captcha))
             error = "Incorrect captcha verification code, please try again!";
         else if (title.Length < Core.settings[SETTINGS_KEY].getInt(SETTINGS_IMAGES_TITLE_MIN) || title.Length > Core.settings[SETTINGS_KEY].getInt(SETTINGS_TITLE_MAX))
             error = "Title must be between " + Core.settings[SETTINGS_KEY][SETTINGS_TITLE_MIN] + " to " + Core.settings[SETTINGS_KEY][SETTINGS_IMAGES_TITLE_MAX] + " characters in length!";
         else if (image.ContentLength == 0)
             error = "The uploaded image contains no data, please try again!";
         else if (image.ContentLength > Core.settings[SETTINGS_KEY].getInt(SETTINGS_IMAGES_MAXSIZE))
             error = "The uploaded image is too large - maximum size allowed is " + Misc.Plugins.getBytesString(Core.settings[SETTINGS_KEY].getLong(SETTINGS_IMAGES_MAXSIZE)) + "!";
         else if (!Core.settings[SETTINGS_KEY].getCommaArrayContains(SETTINGS_IMAGE_TYPES, image.ContentType))
             error = "Invalid image type - ensure you've uploaded an actual image!";
         else
         {
             // Compress the image data for database storage
             byte[] imageData = compressImageData(image.InputStream, Core.settings[SETTINGS_KEY].getInt(SETTINGS_IMAGES_MAXWIDTH), Core.settings[SETTINGS_KEY].getInt(SETTINGS_IMAGES_MAXHEIGHT));
             if (imageData == null)
                 error = "Failed to process image - please try your request again or ensure the uploaded image is not corrupt!";
             else
             {
                 // Write the data to the database
                 Dictionary<string, object> imageParams = new Dictionary<string, object>();
                 imageParams.Add("title", title);
                 imageParams.Add("userid", HttpContext.Current.User.Identity.Name);
                 imageParams.Add("data", imageData);
                 string imageid = conn.Query_Scalar_Parameters("INSERT INTO articles_images (title, userid, data, datetime) VALUES(@title, @userid, @data, NOW()); SELECT LAST_INSERT_ID();", imageParams).ToString();
                 // Redirect the user to view the image
                 conn.Disconnect();
                 response.Redirect(pageElements["URL"] + "/articles/images/view/" + imageid);
             }
         }
     }
     // Output form
     content.Append(
         Core.templates["articles"]["image_uploader"]
         .Replace("<ERROR>", error != null ? Core.templates[pageElements["TEMPLATE"]]["error"].Replace("<ERROR>", error) : string.Empty)
         .Replace("<TITLE>", HttpUtility.HtmlEncode(title))
         );
     pageElements["TITLE"] = "Articles - Image Store - Upload";
 }
Exemple #2
0
        /// <summary>
        /// Used to create/modify an article.
        /// </summary>
        /// <param name="pluginid"></param>
        /// <param name="conn"></param>
        /// <param name="pageElements"></param>
        /// <param name="request"></param>
        /// <param name="response"></param>
        public static void pageArticle_Editor(string pluginid, Connector conn, ref Misc.PageElements pageElements, HttpRequest request, HttpResponse response)
        {
            // Check the user is logged-in, else redirect to the login page
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                response.Redirect(pageElements["URL"] + "/login", true);

            // Load the users permissions and check they're able to create articles
            Result perms = conn.Query_Read("SELECT ug.access_media_create, ug.access_media_publish, ug.access_media_edit, ug.access_admin FROM bsa_users AS u LEFT OUTER JOIN bsa_user_groups AS ug ON ug.groupid=u.groupid WHERE u.userid='" + Utils.Escape(HttpContext.Current.User.Identity.Name) + "'");
            if (perms.Rows.Count != 1 || !perms[0]["access_media_create"].Equals("1")) return;
            bool permAdmin = perms[0]["access_admin"].Equals("1");
            bool permEdit = perms[0]["access_media_edit"].Equals("1");
            bool permPublish = perms[0]["access_media_publish"].Equals("1");

            string error = null;
            Result preData = null;
            ResultRow preDataRow = null;
            // Check if we're modifying an existing article, if so we'll load the data
            string articleid = request.QueryString["articleid"];
            if (articleid != null && Misc.Plugins.isNumeric(articleid))
            {
                // Attempt to load the pre-existing article's data
                preData = conn.Query_Read("SELECT a.*, at.relative_url, at.pdf_name, GROUP_CONCAT(at2.keyword SEPARATOR ',') AS tags FROM articles AS a LEFT OUTER JOIN articles_tags AS at2 ON (EXISTS (SELECT tagid FROM articles_tags_article WHERE tagid=at2.tagid AND articleid='" + Utils.Escape(articleid) + "')) LEFT OUTER JOIN articles_thread AS at ON at.threadid=a.threadid WHERE articleid='" + Utils.Escape(articleid) + "'");
                if (preData.Rows.Count != 1) preData = null;
                else
                    preDataRow = preData[0];
            }
            // Check for postback
            string title = request.Form["title"];
            string body = request.Form["body"];
            string relativeUrl = request.Form["relative_url"] ?? request.QueryString["relative_url"];
            string tags = request.Form["tags"];
            bool allowHTML = request.Form["allow_html"] != null;
            bool allowComments = request.Form["allow_comments"] != null;
            bool showPane = request.Form["show_pane"] != null;
            bool inheritThumbnail = request.Form["inherit_thumbnail"] != null;
            bool updateExisting = request.Form["update_existing"] != null;
            HttpPostedFile thumbnail = request.Files["thumbnail"];
            if (title != null && body != null && relativeUrl != null && tags != null)
            {
                // Validate
                if (title.Length < Core.settings[SETTINGS_KEY].getInt(SETTINGS_TITLE_MIN) || title.Length > Core.settings[SETTINGS_KEY].getInt(SETTINGS_TITLE_MAX))
                    error = "Title must be " + Core.settings[SETTINGS_KEY][SETTINGS_TITLE_MIN] + " to " + Core.settings[SETTINGS_KEY][SETTINGS_TITLE_MAX] + " characters in length!";
                else if (body.Length < Core.settings[SETTINGS_KEY].getInt(SETTINGS_BODY_MIN) || body.Length > Core.settings[SETTINGS_KEY].getInt(SETTINGS_BODY_MAX))
                    error = "Body must be " + Core.settings[SETTINGS_KEY][SETTINGS_BODY_MIN] + " to " + Core.settings[SETTINGS_KEY][SETTINGS_BODY_MAX] + " characters in length!";
                else if (body.Replace(" ", string.Empty).Length == 0)
                    error = "Body cannot be empty/contain just spaces!";
                else if (thumbnail != null && thumbnail.ContentLength > 0 && thumbnail.ContentLength > Core.settings[SETTINGS_KEY].getInt(SETTINGS_THUMBNAIL_MAXSIZE))
                    error = "Thumbnail cannot exceed " + Core.settings[SETTINGS_KEY][SETTINGS_THUMBNAIL_MAXSIZE] + " bytes (" + Misc.Plugins.getBytesString(Core.settings[SETTINGS_KEY].getInt(SETTINGS_THUMBNAIL_MAXSIZE)) + ")!";
                else if (thumbnail != null && thumbnail.ContentLength > 0 && !Core.settings[SETTINGS_KEY].getCommaArrayContains(SETTINGS_IMAGE_TYPES, thumbnail.ContentType))
                    error = "Invalid thumbnail image format - ensure you uploaded an image!";
                else if ((error = validRelativeUrl(relativeUrl, Core.settings[SETTINGS_KEY].getInt(SETTINGS_RELATIVE_URL_MAXCHUNKS), Core.settings[SETTINGS_KEY].getInt(SETTINGS_RELATIVE_URL_CHUNK_MIN), Core.settings[SETTINGS_KEY].getInt(SETTINGS_RELATIVE_URL_CHUNK_MAX))) != null)
                    ;
                else
                {
                    // Verify the user has not exceeded post limits for today - unless they're admin, we'll just skip the checks
                    ResultRow postLimits = permAdmin ? null : conn.Query_Read("SELECT (SELECT COUNT('') FROM articles WHERE userid='" + Utils.Escape(HttpContext.Current.User.Identity.Name) + "' AND datetime >= DATE_SUB(NOW(), INTERVAL 1 HOUR)) AS articles_hour, (SELECT COUNT('') FROM articles WHERE userid='" + Utils.Escape(HttpContext.Current.User.Identity.Name) + "' AND datetime >= DATE_SUB(NOW(), INTERVAL 1 DAY)) AS articles_day")[0];
                    if (postLimits != null && int.Parse(postLimits["articles_hour"]) >= Core.settings[SETTINGS_KEY].getInt(SETTINGS_ARTICLES_EDIT_PER_HOUR))
                        error = "You've already posted the maximum amount of articles allowed within an hour, please try again later!";
                    else if (postLimits != null && int.Parse(postLimits["articles_day"]) >= Core.settings[SETTINGS_KEY].getInt(SETTINGS_ARTICLES_EDIT_PER_DAY))
                        error = "You've already posted the maximum amount of articles allowed today, please try again later!";
                    else
                    {
                        // Verify tags
                        ArticleTags parsedTags = getTags(tags, Core.settings[SETTINGS_KEY].getInt(SETTINGS_TAGS_TITLE_MIN), Core.settings[SETTINGS_KEY].getInt(SETTINGS_TAGS_TITLE_MAX), Core.settings[SETTINGS_KEY].getInt(SETTINGS_TAGS_MAX));
                        if (parsedTags.error != null) error = parsedTags.error;
                        else
                        {
                            // Check if we're inserting, else perhaps inheriting, a thumbnail
                            string thumbnailid = null;
                            if (thumbnail != null && thumbnail.ContentLength > 0)
                            {
                                byte[] imageData = compressImageData(thumbnail.InputStream, Core.settings[SETTINGS_KEY].getInt(SETTINGS_THUMBNAIL_MAXWIDTH), Core.settings[SETTINGS_KEY].getInt(SETTINGS_THUMBNAIL_MAXHEIGHT));
                                if (imageData != null)
                                {
                                    // Success - insert thumbnail and get thumbnailid
                                    Dictionary<string, object> thumbParams = new Dictionary<string, object>();
                                    thumbParams.Add("thumb", imageData);
                                    thumbnailid = conn.Query_Scalar_Parameters("INSERT INTO articles_thumbnails (data) VALUES(@thumb); SELECT LAST_INSERT_ID();", thumbParams).ToString();
                                }
                                else
                                    error = "Failed to process thumbnail image, please try again or report this to the site administrator!";
                            }
                            else if (inheritThumbnail && preDataRow != null && preDataRow["thumbnailid"].Length != 0)
                            {
                                // Grab pre-existing thumbnailid
                                thumbnailid = preDataRow["thumbnailid"];
                            }
                            // Ensure no thumbnail processing errors occur, else do not continue
                            if (error == null)
                            {
                                // Format the body formatting for caching
                                StringBuilder cached = new StringBuilder(body);
                                articleViewRebuildCache(conn, ref cached, allowHTML, ref pageElements);

                                // Posted data is valid, check if the thread exists - else create it
                                bool updateArticle = false; // If the article is being modified and it has not been published and it's owned by the same user -> update it (user may make a small change)
                                string threadid;
                                Result threadCheck = conn.Query_Read("SELECT threadid FROM articles_thread WHERE relative_url='" + Utils.Escape(relativeUrl) + "'");
                                if (threadCheck.Rows.Count == 1)
                                {
                                    // -- Thread exists
                                    threadid = threadCheck[0]["threadid"];
                                    // -- Check if to update the article if the articleid has been specified
                                    if (articleid != null)
                                    {
                                        Result updateCheck = conn.Query_Read("SELECT userid, published FROM articles WHERE articleid='" + Utils.Escape(articleid) + "' AND threadid='" + Utils.Escape(threadid) + "'");
                                        // If the article is unpublished *or* update-existing is true, set the update flag to true
                                        bool ucPublished = updateCheck[0]["published"].Equals("1");
                                        if (updateCheck.Rows.Count == 1 && ((updateCheck[0]["userid"] == HttpContext.Current.User.Identity.Name && !ucPublished) || (updateExisting && (permAdmin || permEdit))))
                                            updateArticle = true;
                                    }
                                }
                                else
                                    // -- Create thread
                                    threadid = conn.Query_Scalar("INSERT INTO articles_thread (relative_url) VALUES('" + Utils.Escape(relativeUrl) + "'); SELECT LAST_INSERT_ID();").ToString();

                                // Check if to insert or update the article
                                if (updateArticle)
                                {
                                    StringBuilder query = new StringBuilder();
                                    // Update the article
                                    query
                                        .Append("UPDATE articles SET title='").Append(Utils.Escape(title))
                                        .Append("', thumbnailid=").Append(thumbnailid != null ? "'" + Utils.Escape(thumbnailid) + "'" : "NULL")
                                        .Append(", body='").Append(Utils.Escape(body))
                                        .Append("', body_cached='").Append(Utils.Escape(cached.ToString()))
                                        .Append("', allow_comments='").Append(allowComments ? "1" : "0")
                                        .Append("', allow_html='").Append(allowHTML ? "1" : "0")
                                        .Append("', show_pane='").Append(showPane ? "1" : "0").Append("' WHERE articleid='").Append(Utils.Escape(articleid)).Append("';");
                                    // Delete the previous tags
                                    query.Append("DELETE FROM articles_tags_article WHERE articleid='" + Utils.Escape(articleid) + "';");
                                    // Delete the previous images associated with the article
                                    query.Append("DELETE FROM articles_images_links WHERE articleid='" + Utils.Escape(articleid) + "'");
                                    // -- Execute query
                                    conn.Query_Execute(query.ToString());
                                }
                                else
                                {
                                    // Insert article and link to the thread
                                    StringBuilder query = new StringBuilder();
                                    query
                                        .Append("INSERT INTO articles (threadid, title, userid, body, body_cached, moderator_userid, published, allow_comments, allow_html, show_pane, thumbnailid, datetime) VALUES('")
                                        .Append(Utils.Escape(threadid))
                                        .Append("', '").Append(Utils.Escape(title))
                                        .Append("', '").Append(Utils.Escape(HttpContext.Current.User.Identity.Name))
                                        .Append("', '").Append(Utils.Escape(body))
                                        .Append("', '").Append(Utils.Escape(cached.ToString()))
                                        .Append("', ").Append(permPublish ? "'" + Utils.Escape(HttpContext.Current.User.Identity.Name) + "'" : "NULL")
                                        .Append(", '").Append(permPublish ? "1" : "0")
                                        .Append("', '").Append(allowComments ? "1" : "0")
                                        .Append("', '").Append(allowHTML ? "1" : "0")
                                        .Append("', '").Append(showPane ? "1" : "0")
                                        .Append("', ").Append(thumbnailid != null ? "'" + Utils.Escape(thumbnailid) + "'" : "NULL")
                                        .Append(", NOW()); SELECT LAST_INSERT_ID();");
                                    articleid = conn.Query_Scalar(query.ToString()).ToString();
                                    // If this was automatically published, set it as the current article for the thread
                                    if (permPublish)
                                        conn.Query_Execute("UPDATE articles_thread SET articleid_current='" + Utils.Escape(articleid) + "' WHERE relative_url='" + Utils.Escape(relativeUrl) + "'");
                                }
                                // Add/update pdf
                                pdfRebuild(pluginid, articleid, title, preData != null ? preDataRow["pdf_name"] : string.Empty, threadid, request);
                                // Add the new tags and delete any tags not used by any other articles, as well as cleanup unused thumbnails
                                StringBuilder finalQuery = new StringBuilder();
                                if (parsedTags.tags.Count > 0)
                                {
                                    StringBuilder tagsInsertQuery = new StringBuilder();
                                    StringBuilder tagsArticleQuery = new StringBuilder();
                                    foreach (string tag in parsedTags.tags)
                                    {
                                        // -- Attempt to insert the tags - if they exist, they wont be inserted
                                        tagsInsertQuery.Append("('" + Utils.Escape(tag) + "'),");
                                        tagsArticleQuery.Append("((SELECT tagid FROM articles_tags WHERE keyword='" + Utils.Escape(tag) + "'), '" + Utils.Escape(articleid) + "'),");
                                    }
                                    // -- Build final query
                                    finalQuery.Append("INSERT IGNORE INTO articles_tags (keyword) VALUES")
                                        .Append(tagsInsertQuery.Remove(tagsInsertQuery.Length - 1, 1).ToString())
                                        .Append("; INSERT IGNORE INTO articles_tags_article (tagid, articleid) VALUES")
                                        .Append(tagsArticleQuery.Remove(tagsArticleQuery.Length - 1, 1).ToString())
                                        .Append(";");
                                }
                                // Add any linked imagery
                                // -- Find the unique valid image IDs
                                List<string> images = new List<string>();
                                foreach (Match m in Regex.Matches(body, REGEX_IMAGE_STORE, RegexOptions.Multiline))
                                    if (!images.Contains(m.Groups[1].Value))
                                        images.Add(m.Groups[1].Value);
                                foreach (Match m in Regex.Matches(body, REGEX_IMAGE_STORE_CUSTOM_W, RegexOptions.Multiline))
                                    if (!images.Contains(m.Groups[3].Value))
                                        images.Add(m.Groups[3].Value);
                                foreach (Match m in Regex.Matches(body, REGEX_IMAGE_STORE_CUSTOM_WH, RegexOptions.Multiline))
                                    if (!images.Contains(m.Groups[3].Value))
                                        images.Add(m.Groups[3].Value);
                                if (images.Count != 0)
                                {
                                    // -- Insert all the valid IDs which exist in the actual articles_images table
                                    finalQuery.Append("INSERT IGNORE INTO articles_images_links (articleid, imageid) SELECT '" + Utils.Escape(articleid) + "' AS articleid, imageid FROM articles_images WHERE imageid IN (");
                                    foreach (string s in images)
                                        finalQuery.Append("'").Append(Utils.Escape(s)).Append("',");
                                    finalQuery.Remove(finalQuery.Length - 1, 1).Append(");");
                                }
                                // -- This will delete any tags in the main table no longer used in the articles tags table
                                finalQuery.Append(QUERY_TAGS_CLEANUP);
                                // -- This will delete any unused thumbnail images
                                finalQuery.Append(QUERY_THUMBNAIL_CLEANUP);
                                // -- This will log the event
                                finalQuery.Append(insertEvent(updateArticle ? RecentChanges_EventType.Edited : RecentChanges_EventType.Created, HttpContext.Current.User.Identity.Name, articleid, threadid));
                                // -- Execute final query
                                conn.Query_Execute(finalQuery.ToString());
                                // Redirect to the new article
                                conn.Disconnect();
                                response.Redirect(pageElements["URL"] + "/article/" + articleid, true);
                            }
                        }
                    }
                }
            }
            // Display form
            pageElements["CONTENT"] = Core.templates["articles"]["editor"]
                .Replace("<ERROR>", error != null ? Core.templates[pageElements["TEMPLATE"]]["error"].Replace("<ERROR>", HttpUtility.HtmlEncode(error)) : string.Empty)
                .Replace("<PARAMS>", preData != null ? "articleid=" + HttpUtility.UrlEncode(preData[0]["articleid"]) : string.Empty)
                .Replace("<TITLE>", HttpUtility.HtmlEncode(title ?? (preDataRow != null ? preDataRow["title"] : string.Empty)))
                .Replace("<RELATIVE_PATH>", HttpUtility.HtmlEncode(relativeUrl ?? (preDataRow != null ? preDataRow["relative_url"] : string.Empty)))
                .Replace("<TAGS>", HttpUtility.HtmlEncode(tags ?? (preDataRow != null ? preDataRow["tags"] : string.Empty)))
                .Replace("<ALLOW_HTML>", allowHTML || (title == null && preDataRow != null && preDataRow["allow_html"].Equals("1")) ? "checked" : string.Empty)
                .Replace("<ALLOW_COMMENTS>", allowComments || (title == null && preDataRow != null && preDataRow["allow_comments"].Equals("1")) ? "checked" : string.Empty)
                .Replace("<SHOW_PANE>", showPane || (title == null && preDataRow != null && preDataRow["show_pane"].Equals("1")) ? "checked" : string.Empty)
                .Replace("<INHERIT>", inheritThumbnail || (title == null && preDataRow != null && preDataRow["thumbnailid"].Length > 0) ? "checked" : string.Empty)
                .Replace("<UPDATE_EXISTING>", updateExisting || (title == null && preDataRow != null) ? "checked" : string.Empty)
                .Replace("<BODY>", HttpUtility.HtmlEncode(body ?? (preDataRow != null ? preDataRow["body"] : string.Empty)))
                ;
            // Set flags
            // -- Update existing checkbox
            if ((permAdmin || permEdit) && preData != null)
                pageElements.setFlag("UPDATE_EXISTING");
            // Finalize page
            Misc.Plugins.addHeaderJS(pageElements["URL"] + "/Content/JS/Article.js", ref pageElements);
            Misc.Plugins.addHeaderCSS(pageElements["URL"] + "/Content/CSS/Article.css", ref pageElements);
            Misc.Plugins.addHeaderCSS(pageElements["URL"] + "/Content/CSS/Common.css", ref pageElements);
            // Add includes
            Common.formatProvider_formatIncludes(request, response, conn, ref pageElements, true, true);
            pageElements["TITLE"] = "Articles - Editor";
        }