public void Replace_Custom_Code_Tags_With_Pre_Tags(string input, string expected) { var pf = new PostFormatter(); var output = pf.Prettify(input); Assert.AreEqual(output, expected); }
public void Not_Change_String_Without_Code_Tags(string input, string expected) { var pf = new PostFormatter(); var output = pf.Prettify(input); Assert.AreEqual(output, expected); }
public void Replace_Env_NewLine_With_Br_Tag() { var input = $"Here is a post {Environment.NewLine} with a newline."; var expected = $"Here is a post <br /> with a newline."; var pf = new PostFormatter(); var output = pf.Prettify(input); Assert.AreEqual(output, expected); }
public async Task <IActionResult> Search(int threadId, string query = "") { try { if (User.Identity.IsAuthenticated) { ViewBag.CurrentAdmin = _db.Admin.First(a => a.Email == User.Identity.Name); } var postsFiles = new Dictionary <Post, List <File> >(); if (!string.IsNullOrWhiteSpace(query) || !string.IsNullOrEmpty(query)) { if (ModelState.IsValid) { try { var posts = _db.Post.Where(p => p.ThreadId == threadId && (p.Comment.Contains(query) || p.Subject.Contains(query))) .Include(p => p.File).Take(50).ToList(); foreach (var post in posts) { post.Comment = PostFormatter.GetFormattedPostText(post); postsFiles.Add(post, post.File.ToList()); } } catch (InvalidOperationException) { return(NotFound()); } } } ViewBag.Thread = _db.Thread.Include(t => t.Board).First(t => t.ThreadId == threadId); ViewBag.Board = ViewBag.Thread.Board; ViewBag.PostsFiles = postsFiles; } catch (InvalidOperationException) { return(NotFound()); } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); return(StatusCode(500)); } return(View()); }
public async Task <IActionResult> Report(int postId) { var ipHash = _md5.ComputeHash(HttpContext.Connection.RemoteIpAddress.GetAddressBytes()) .GetString(); var anon = new Anon(ipHash, IpCheck.UserIsBanned(_db, ipHash)); ViewBag.UserIpHash = anon.IpHash; ViewBag.UserIsBanned = false; if (anon.IsBanned) { ViewBag.UserIsBanned = anon.IsBanned; var ban = _db.Ban.First(b => b.AnonIpHash == anon.IpHash); ViewBag.BanReason = ban.Reason; ViewBag.BanEnd = DateTimeOffset.FromUnixTimeSeconds(ban.Term).ToLocalTime(); } try { var post = _db.Post.Include(p => p.File) .Include(p => p.Admin) .First(p => p.PostId == postId) ?? throw new Exception(); ViewBag.Board = _collection.Boards.First(brd => brd.BoardId == post.BoardId); ViewBag.Thread = _db.Thread.First(t => t.ThreadId == post.ThreadId); post.Comment = PostFormatter.GetFormattedPostText(post); ViewBag.PostFiles = new KeyValuePair <Post, List <File> >(post, post.File.ToList()); return(View()); } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); return(NotFound()); } }
public PostFormatterTests() { _formatter = new PostFormatter(_htmlMock.Object); _htmlMock.SetupGet(x => x.DivForTextStart).Returns(""); _htmlMock.SetupGet(x => x.DivEnd).Returns(""); _htmlMock.Setup(x => x.Blockquote(It.IsAny <string>())) .Returns((string text) => $"@{text}@"); _htmlMock.Setup(x => x.Centered(It.IsAny <string>())).Returns((string text) => $"c[{text}]"); _htmlMock.Setup(x => x.FloatRight(It.IsAny <string>())) .Returns((string text) => $"fr[{text}]"); _htmlMock.Setup(x => x.Image(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <int>(), It.IsAny <int>())) .Returns((string url, string src, int height, int width) => $"<{url}/{src}/{height}/{width}>"); _htmlMock.Setup(x => x.Link(It.IsAny <string>(), It.IsAny <string>())) .Returns((string url, string title) => $"<{url}-{title}>"); _htmlMock.Setup(x => x.LjCut(It.IsAny <string>())) .Returns((string text) => text); _htmlMock.Setup(x => x.Strikeout(It.IsAny <string>())) .Returns((string text) => $"={text}="); }
private string build_page_html(string board, string threadId, PostFormatter[] thread_data, string notes) { StringBuilder pageHtml = new StringBuilder(Properties.Resources.zip_page_template); StringBuilder body = new StringBuilder(); { body.Append(thread_data[0].ToString(true)); body.Replace("{post:link}", string.Format("#p{0}", thread_data[0].PostID)); for (int i = 1; i < thread_data.Length; i++) { body.Append(thread_data[i].ToString(true)); } } pageHtml.Replace("{title}", string.Format("/{0}/ Thread No. {1}", board, threadId)); pageHtml.Replace("{board-letter}", board); pageHtml.Replace("{notes}", System.Web.HttpUtility.HtmlEncode(notes)); pageHtml.Replace("{thread-id}", threadId); pageHtml.Replace("{thread-posts}", body.ToString()); return pageHtml.ToString(); }
private PostFormatter load_post_data_str(string data, bool isop) { JsonObject post_data = JsonConvert.Import<JsonObject>(data); string[] keys = post_data.Names.Cast<string>().ToArray(); PostFormatter pf = new PostFormatter(); foreach (JsonMember member in post_data) { switch (member.Name) { case "RawComment": pf.Comment = Convert.ToString(member.Value); continue; case "Email": pf.Email = Convert.ToString(member.Value); continue; case "Name": pf.Name = Convert.ToString(member.Value); continue; case "PosterID": pf.PosterID = Convert.ToString(member.Value); continue; case "Subject": pf.Subject = Convert.ToString(member.Value); continue; case "Trip": pf.Trip = Convert.ToString(member.Value); continue; case "ID": pf.PostID = Convert.ToInt32(member.Value); continue; case "Time": try { pf.Time = DateTime.Parse(member.Value.ToString()); } catch { } continue; case "FileHash": { FileFormatter f = new FileFormatter(); f.PostID = pf.PostID; f.FileName = Convert.ToString(post_data["FileName"]); f.Hash = Convert.ToString(post_data["FileHash"]); f.ThumbName = Convert.ToString(post_data["ThumbTime"]); f.Height = Convert.ToInt32(post_data["FileHeight"]); f.Width = Convert.ToInt32(post_data["FileWidth"]); f.Size = Convert.ToInt32(post_data["FileSize"]); pf.MyFile = f; continue; } case "Sticky": pf.IsSticky = Convert.ToBoolean(member.Value); continue; case "Closed": pf.IsLocked = Convert.ToBoolean(member.Value); continue; } } pf.Type = isop ? PostFormatter.PostType.OP : PostFormatter.PostType.Reply; return pf; }
private PostFormatter load_post_data_str(string data, bool isop) { JsonObject post_data = JsonConvert.Import <JsonObject>(data); string[] keys = post_data.Names.Cast <string>().ToArray(); PostFormatter pf = new PostFormatter(); foreach (JsonMember member in post_data) { switch (member.Name) { case "RawComment": pf.Comment = Convert.ToString(member.Value); continue; case "Email": pf.Email = Convert.ToString(member.Value); continue; case "Name": pf.Name = Convert.ToString(member.Value); continue; case "PosterID": pf.PosterID = Convert.ToString(member.Value); continue; case "Subject": pf.Subject = Convert.ToString(member.Value); continue; case "Trip": pf.Trip = Convert.ToString(member.Value); continue; case "ID": pf.PostID = Convert.ToInt32(member.Value); continue; case "Time": try { pf.Time = DateTime.Parse(member.Value.ToString()); } catch { } continue; case "FileHash": { FileFormatter f = new FileFormatter(); f.PostID = pf.PostID; f.FileName = Convert.ToString(post_data["FileName"]); f.Hash = Convert.ToString(post_data["FileHash"]); f.ThumbName = Convert.ToString(post_data["ThumbTime"]); f.Height = Convert.ToInt32(post_data["FileHeight"]); f.Width = Convert.ToInt32(post_data["FileWidth"]); f.Size = Convert.ToInt32(post_data["FileSize"]); pf.MyFile = f; continue; } case "Sticky": pf.IsSticky = Convert.ToBoolean(member.Value); continue; case "Closed": pf.IsLocked = Convert.ToBoolean(member.Value); continue; } } pf.Type = isop ? PostFormatter.PostType.OP : PostFormatter.PostType.Reply; return(pf); }
public PostFormatter[] GetThread(string board, string id) { string thread_dir_path = Path.Combine(Program.post_files_dir, board, id.ToString()); DirectoryInfo info = new DirectoryInfo(thread_dir_path); if (!info.Exists) { return(new PostFormatter[] { }); } // optimized thread path string opt_path = Path.Combine(thread_dir_path, id + "-opt.json"); List <PostFormatter> thread_pf = new List <PostFormatter>(); if (File.Exists(opt_path)) { JsonObject thread_data = JsonConvert.Import <JsonObject>(File.ReadAllText(opt_path)); string data; if (thread_data.Names.Cast <string>().Contains("op")) { data = thread_data["op"].ToString(); if (!string.IsNullOrEmpty(data)) { thread_pf.Add(load_post_data_str(data, true)); // remove the op post thread_data.Remove("op"); } } // sort the replies by their id foreach (string key in thread_data.Names.Cast <object>().OrderBy(x => Convert.ToInt32(x))) { data = thread_data[key].ToString(); if (!string.IsNullOrEmpty(data)) { thread_pf.Add(load_post_data_str(data, false)); } } } else { string data; string op = Path.Combine(thread_dir_path, "op.json"); if (File.Exists(op)) { data = File.ReadAllText(op); if (!string.IsNullOrEmpty(data)) { thread_pf.Add(load_post_data_str(data, true)); } } foreach (string file in Directory.EnumerateFiles(thread_dir_path, "*.json", SearchOption.TopDirectoryOnly).OrderBy(x => Path.GetFileNameWithoutExtension(x))) { if (!file.EndsWith("op.json")) { data = File.ReadAllText(file); if (!string.IsNullOrWhiteSpace(data)) { try { PostFormatter post = load_post_data_str(data, false); thread_pf.Add(post); } catch (JsonException) { File.Delete(file); } catch (Exception) { } } } } } return(thread_pf.ToArray()); }
public async Task <IActionResult> Thread(int id) { var ipHash = _md5.ComputeHash(HttpContext.Connection.RemoteIpAddress.GetAddressBytes()) .GetString(); var anon = new Anon(ipHash, IpCheck.UserIsBanned(_db, ipHash)); ViewBag.UserIpHash = anon.IpHash; ViewBag.UserIsBanned = false; ViewBag.Id = 0; if (anon.IsBanned) { ViewBag.UserIsBanned = anon.IsBanned; var ban = _db.Ban.First(b => b.AnonIpHash == anon.IpHash); ViewBag.BanReason = ban.Reason; ViewBag.BanEnd = DateTimeOffset.FromUnixTimeSeconds(ban.Term).ToLocalTime(); } if (User.Identity.IsAuthenticated) { ViewBag.CurrentAdmin = _db.Admin.First(a => a.Email == User.Identity.Name); } try { using (_db) { try { var thread = _db.Thread.Where(t => t.ThreadId == id) .Include(t => t.Board) .ToList()[0]; var posts = _db.Post.Where(p => p.ThreadId == id) .Include(p => p.File) .Include(p => p.Admin) .ToList(); var postsFiles = new Dictionary <Post, List <File> >(); ViewBag.PinnedPost = new KeyValuePair <Post, List <File> >(null, null); foreach (var post in posts) { post.Comment = PostFormatter.GetFormattedPostText(post); if (post.IsPinned) { ViewBag.PinnedPost = new KeyValuePair <Post, List <File> >(post, post.File.ToList()); continue; } postsFiles.Add(post, post.File.ToList()); } ViewBag.Board = thread.Board; ViewBag.Thread = thread; ViewBag.UserIsOp = IpCheck.UserIsOp(thread, anon.IpHash); ViewBag.PostsFiles = postsFiles; } catch (ArgumentOutOfRangeException) { return(NotFound()); } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); } } } catch (InvalidOperationException) { return(NotFound()); } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); } return(View()); }
public async Task <IActionResult> AddPost(Post post, List <IFormFile> files, bool sage, bool isWrittenByOp = false) { try { var ipHash = _md5.ComputeHash(HttpContext.Connection.RemoteIpAddress.GetAddressBytes()) .GetString(); var anon = new Anon(ipHash, IpCheck.UserIsBanned(_db, ipHash)); if (anon.IsBanned) { return(RedirectToAction("YouAreBanned", "Ban")); } post.Comment = PostFormatter.GetHtmlTrimmedString(post.Comment); post.AnonIpHash = ipHash; post.TimeInUnixSeconds = DateTimeOffset.Now.ToUnixTimeSeconds(); if (User.Identity.IsAuthenticated) { var admin = _db.Admin.First(a => a.Email == User.Identity.Name); post.AnonName = admin.Login; post.Admin = admin; } if (ModelState.IsValid) { DbAccess.AddPostToThread(_db, post, sage, isWrittenByOp); if (files.Count > 0) { var fileDirectory = Path.Combine(_env.WebRootPath, "postImages"); var thumbNailDirectory = Path.Combine(_env.WebRootPath, "thumbnails"); foreach (var file in files) { if (file.Length > 0) { switch (Path.GetExtension(file.FileName)) { case ".jpeg": case ".jpg": case ".png": { var imageThumbnailCreator = new ImageThumbnailCreator(file, fileDirectory, thumbNailDirectory); imageThumbnailCreator.CreateThumbnail(); DbAccess.AddFilesToPost(_db, post, imageThumbnailCreator.FileInfo); break; } case ".gif": { var gifThumbnailCreator = new GifThumbnailCreator(file, fileDirectory, thumbNailDirectory); gifThumbnailCreator.CreateThumbnail(); DbAccess.AddFilesToPost(_db, post, gifThumbnailCreator.FileInfo); break; } } } else { ModelState.AddModelError("FileLengthNotValid", "Файл пустой."); } } } await LogIntoFile(_logDirectory, string.Concat("Added new post: ", post.PostId, "at thread: ", post.ThreadId), LoggingInformationKind.Info); } else { return(StatusCode(500)); } } catch (InvalidOperationException) { return(NotFound()); } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); } return(RedirectToAction("Thread", new { id = post.ThreadId })); }
public async Task <IActionResult> AddThread(Post post, List <IFormFile> files) { try { var ipHash = _md5.ComputeHash(HttpContext.Connection.RemoteIpAddress.GetAddressBytes()) .GetString(); var anon = new Anon(ipHash, IpCheck.UserIsBanned(_db, ipHash)); if (anon.IsBanned) { return(RedirectToAction("YouAreBanned", "Ban")); } if (ModelState.IsValid) { var board = _db.Board.First(b => b.BoardId == post.BoardId); if (_db.Thread.Count(t => t.BoardId == post.BoardId) >= 20) { return(RedirectToAction("Board", new { prefix = board.Prefix })); } post.AnonIpHash = ipHash; if (!string.IsNullOrEmpty(post.AnonName)) { post.AnonName = PostFormatter.GetHtmlTrimmedString(post.AnonName); } post.Comment = PostFormatter.GetHtmlTrimmedString(post.Comment); post.IsWrittenByOp = true; if (User.Identity.IsAuthenticated) { var admin = _db.Admin.First(a => a.Email == User.Identity.Name); post.AnonName = admin.Login; post.Admin = admin; } DbAccess.AddThreadToBoard(_db, ref post); if (files.Count > 0) { var fileDirectory = Path.Combine(_env.WebRootPath, "postImages"); var thumbNailDirectory = Path.Combine(_env.WebRootPath, "thumbnails"); foreach (var file in files) { if (file.Length > 0) { switch (Path.GetExtension(file.FileName)) { case ".jpeg": case ".jpg": case ".png": { var imageThumbnailCreator = new ImageThumbnailCreator(file, fileDirectory, thumbNailDirectory); imageThumbnailCreator.CreateThumbnail(); DbAccess.AddFilesToPost(_db, post, imageThumbnailCreator.FileInfo); break; } case ".gif": { var gifThumbnailCreator = new GifThumbnailCreator(file, fileDirectory, thumbNailDirectory); gifThumbnailCreator.CreateThumbnail(); DbAccess.AddFilesToPost(_db, post, gifThumbnailCreator.FileInfo); break; } } } else { ModelState.AddModelError("FileLengthNotValid", "Файл пустой."); } } } await LogIntoFile(_logDirectory, string.Concat("Added new thread: ", post.ThreadId), LoggingInformationKind.Info); return(RedirectToAction("Thread", "Thread", new { id = post.ThreadId })); } } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); Console.WriteLine(e); return(StatusCode(500)); } return(RedirectToAction("Board")); }
public async Task <IActionResult> Board(string prefix, int page = 1) { var ipHash = _md5.ComputeHash(HttpContext.Connection.RemoteIpAddress.GetAddressBytes()) .GetString(); var anon = new Anon(ipHash, IpCheck.UserIsBanned(_db, ipHash)); ViewBag.UserIpHash = anon.IpHash; ViewBag.UserIsBanned = false; if (anon.IsBanned) { ViewBag.UserIsBanned = anon.IsBanned; var ban = _db.Ban.First(b => b.AnonIpHash == anon.IpHash); ViewBag.BanReason = ban.Reason; ViewBag.BanEnd = DateTimeOffset.FromUnixTimeSeconds(ban.Term).ToLocalTime(); } ViewBag.Id = 0; ViewBag.Page = page; try { ViewBag.Board = _collection.Boards.First(brd => brd.Prefix == prefix); var allThreads = new List <KeyValuePair <Thread, List <KeyValuePair <Post, List <File> > > > >(); var boards = _db.Board.Where(b => b.Prefix == prefix).Include(b => b.Thread).ToList(); Board board; if (boards.Count > 0) { board = boards[0]; ViewBag.FileLimit = board.FileLimit; } else { return(NotFound()); } ViewBag.ThreadCount = board.Thread.Count; foreach (var thrd in board.Thread.OrderByDescending(t => t.BumpInUnixTime)) { var thread = _db.Thread.Include(t => t.Post).First(t => t.ThreadId == thrd.ThreadId); if (thread != null) { var postFiles = new List <KeyValuePair <Post, List <File> > >(); if (thread.Post.Count >= 4) { var posts = new List <Post> { thread.Post.ToArray()[0] }; posts.AddRange(thread.Post.ToList().OrderByDescending(p => p.TimeInUnixSeconds).Take(3)); foreach (var post in posts) { var p = _db.Post .Include(pp => pp.File) .Include(pp => pp.Admin) .First(pp => pp.PostId == post.PostId); postFiles.Add(new KeyValuePair <Post, List <File> >(p, p.File.ToList())); } allThreads.Add( new KeyValuePair <Thread, List <KeyValuePair <Post, List <File> > > >(thread, postFiles)); } else if (thread.Post.Count > 0 && thread.Post.Count <= 3) { var p = _db.Post .Include(pp => pp.File) .Include(pp => pp.Admin) .First(pp => pp.ThreadId == thread.ThreadId); postFiles.Add(new KeyValuePair <Post, List <File> >(p, p.File.ToList())); allThreads.Add( new KeyValuePair <Thread, List <KeyValuePair <Post, List <File> > > >(thread, postFiles)); } } } var pageInfo = new PageInfo(page, Constants.BOARD_PAGE_SIZE, allThreads.Count); var pageThreads = new List <KeyValuePair <Thread, List <KeyValuePair <Post, List <File> > > > >(); for (var i = (page - 1) * pageInfo.PageSize; i < page * pageInfo.PageSize; i++) { try { pageThreads.Add(allThreads[i]); } catch (ArgumentOutOfRangeException) { break; } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); return(StatusCode(500)); } } foreach (var pt in pageThreads) { foreach (var pf in pt.Value) { pf.Key.Comment = PostFormatter.GetFormattedPostText(pf.Key); } } ViewBag.PageInfo = pageInfo; ViewBag.BoardViewModel = pageThreads; } catch (InvalidOperationException e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); return(NotFound()); } catch (Exception e) { await LogIntoFile(_logDirectory, string.Concat(e.Message, "\n", e.StackTrace), LoggingInformationKind.Error); return(StatusCode(500)); } return(View()); }