public NanoHttpResponse Handle(NanoHttpRequest request) { Hash hash = new Hash(request.Address.Split('/').Last()); if (hash.Invalid) { return new ErrorHandler(StatusCode.BadRequest, "Invalid hash").Handle(request); } try { var tag = _db.Get(hash).ContainerTag; for (int i = 0; i < _db.GetPostCount(); i++) { var p = _db.GetPost(i); if (p.ContainerTag != null && p.ContainerTag.Equals(tag)) { _db.HideOnce(p.GetHash()); } } return new NanoHttpResponse(StatusCode.Ok, "\n"); } catch (Exception e) { return new ErrorHandler(StatusCode.InternalServerError, e.ToString().Replace("\n", "<br>")).Handle(request); } }
public NanoHttpResponse Handle(NanoHttpRequest request) { Hash hash = new Hash(request.Address.Split('/').Last()); if (hash.Invalid) { return new ErrorHandler(StatusCode.BadRequest, "Invalid hash").Handle(request); } try { if (_db.IsHidden(hash)) { _db.Unhide(hash); } else { _db.Hide(hash); } return new NanoHttpResponse(StatusCode.Ok, "\n"); } catch (Exception e) { return new ErrorHandler(StatusCode.InternalServerError, e.ToString().Replace("\n", "<br>")).Handle(request); } }
public NanoHttpResponse Handle(NanoHttpRequest request) { if (string.IsNullOrEmpty(request.Content)) { return new ErrorHandler(StatusCode.BadRequest, "Empty message").Handle(request); } Hash thread = new Hash(request.Address.Split('/').Last()); if (thread.Invalid) { return new ErrorHandler(StatusCode.BadRequest, "Invalid hash").Handle(request); } var str = Encoding.UTF8.GetString(request.Connection.Raw); str = str.Substring(str.IndexOf("\r\n\r\n") + 4); NanoPost post = null; if (thread.Value != NanoDB.CategoriesHashValue) { post = new NanoPost(thread, "[g]" + GetPostHeader() + "[/g]\n" + str); } else { post = new NanoPost(thread, str); } if (post.Invalid) { NotificationHandler.Instance.AddNotification("Превышен максимальный размер поста."); return new NanoHttpResponse(StatusCode.BadRequest, ""); } if (SpamDetector.IsSpam(post.Message)) { NotificationHandler.Instance.AddNotification("Ваш пост из-за своего содержания будет считаться спамом."); return new NanoHttpResponse(StatusCode.BadRequest, ""); } else { NotificationHandler.Instance.AddNotification( "Сообщение добавлено, " + post.SerializedBytes().Length + " байт ("+post.SerializedString().Length+" симв.)"); if (_db.AddPost(post)) { _db.WriteNewPosts(false); } return new NanoHttpResponse(StatusCode.Ok, post.GetHash().Value); } }
//public event Action<NanoPost> BookmarkAdded = delegate(NanoPost obj) {}; public void Init() { var root = new NanoPost(Hash.CreateZero(), NanoPost.RootStub); AddPost(root, false); RootHash = root.GetHash(); var cat = new NanoPost(RootHash, "[b]КАТЕГОРИИ[/b]\nЧтобы создать новую категорию, ответьте на это сообщение.\nОтветьте на одну из категорий, чтобы создать там тред."); AddPost(cat, false); var cathash = cat.GetHash(); AddPost(new NanoPost(cathash, "[b]Автомобили/Мотоциклы[/b]"), false); AddPost(new NanoPost(cathash, "[b]Бред/Разное[/b]"), false); AddPost(new NanoPost(cathash, "[b]Видеоигры[/b]"), false); AddPost(new NanoPost(cathash, "[b]Выживание[/b]"), false); AddPost(new NanoPost(cathash, "[b]Железо/Софт[/b]"), false); AddPost(new NanoPost(cathash, "[b]Иностранные языки[/b]"), false); AddPost(new NanoPost(cathash, "[b]Кино и ТВ[/b]"), false); AddPost(new NanoPost(cathash, "[b]Книги[/b]"), false); AddPost(new NanoPost(cathash, "[b]Криптоанархия[/b]"), false); AddPost(new NanoPost(cathash, "[b]Музыка[/b]"), false); AddPost(new NanoPost(cathash, "[b]Мода и стиль[/b]"), false); AddPost(new NanoPost(cathash, "[b]Наука[/b]"), false); AddPost(new NanoPost(cathash, "[b]Обсуждение Наноборды[/b]"), false); AddPost(new NanoPost(cathash, "[b]Паранормальное[/b]"), false); AddPost(new NanoPost(cathash, "[b]Политика[/b]"), false); AddPost(new NanoPost(cathash, "[b]Психология[/b]"), false); AddPost(new NanoPost(cathash, "[b]Программирование[/b]"), false); AddPost(new NanoPost(cathash, "[b]Реквесты[/b]"), false); AddPost(new NanoPost(cathash, "[b]Смартфоны/Планшеты[/b]"), false); AddPost(new NanoPost(cathash, "[b]Секс[/b]"), false); AddPost(new NanoPost(cathash, "[b]Спорт[/b]"), false); AddPost(new NanoPost(cathash, "[b]Творчество[/b]"), false); AddPost(new NanoPost(cathash, "[b]Японская культура[/b]"), false); AddPost(new NanoPost(cathash, "[b]18+[/b]"), false); foreach (var p in _posts) { p.Value.NumberTag = int.MaxValue; } try { if (File.Exists(HideList)) { _hideList = new HashSet<string>(File.ReadAllLines(HideList)); } } catch (Exception e) { Logger.LogError("Error wile reading hide.list\n" + e.ToString()); } }
private NanoHttpResponse HandleSafe(NanoHttpRequest request) { Hash thread = new Hash(request.Address.Split('/').Last()); if (thread.Invalid) { return new ErrorHandler(StatusCode.BadRequest, "Wrong hash format.").Handle(request); } var sb = new StringBuilder(); sb.Append("{ \n \"posts\" : [\n"); var posts = _expanded ? _db.GetExpandedThreadPosts(thread) : _db.GetThreadPosts(thread); for (int i = 0; i < posts.Length; i++) { var p = posts[i]; bool last = i == posts.Length - 1; sb.Append(" {\n \"hash\" : \""); sb.Append(p.GetHash().Value); sb.Append("\", \n \"isHidden\" : \""); sb.Append(_db.IsHidden(p.GetHash()) ? "1" : "0"); sb.Append("\", \n \"replyTo\" : \""); sb.Append(p.ReplyTo.Value); sb.Append("\", \n \"message\" : \""); string s = p.SerializedString().Substring(32); s = s.Replace("\\", "\\\\"); s = s.Replace("\n", "\\n"); s = s.Replace("\"", "\\\""); s = s.Replace("\t", "\\t"); s = s.Replace("\r", "\\r"); sb.Append(s); sb.Append("\"\n }"); if (!last) sb.Append(",\n"); } sb.Append("\n ]\n}"); return new NanoHttpResponse(StatusCode.Ok, sb.ToString(), "application/json; charset=utf-8"); }
private NanoHttpResponse HandleSafe(NanoHttpRequest request) { Hash thread = new Hash(request.Address.Split('/').Last()); if (thread.Invalid) { return new ErrorHandler(StatusCode.BadRequest, "Wrong hash format.").Handle(request); } var sb = new StringBuilder(); ThreadViewHandler.AddHeader(sb); var p = _db.Get(thread); bool corePost = false; if ( p.GetHash().Value == NanoDB.CategoriesHashValue || // создал категорию - не разворачивать все категории p.ReplyTo.Value == NanoDB.CategoriesHashValue) // создал тред в одной из категорий - не разворачивать все треды { corePost = true; } sb.Append( ( p.Message.Strip(true).Replace("\n", "<br/>").ToDiv("postinner", p.GetHash().Value) ).ToDiv("post", "")); sb.Append(((/*">" + p.Message.StripInput().Replace("\n", "\n>") + "\n"*/"").ToTextArea("", "reply").AddBreak() + ("Отправить".ToButton("", "sendbtn", @" var x = new XMLHttpRequest(); x.open('POST', '../write/"+p.GetHash().Value+@"', true); x.send(document.getElementById('reply').value); x.onreadystatechange = function(){ location.replace('/"+(corePost?"thread":"expand")+"/" + p.GetHash().Value + @"');} "))).ToDiv("post", "")); return new NanoHttpResponse(StatusCode.Ok, sb.ToString().ToHtmlBody()); }
public bool Equals(Hash h) { return h != null && h.Value == Value; }
private NanoHttpResponse HandleSafe(NanoHttpRequest request) { _places = HtmlStringExtensions.UpdatePlaces().ToArray(); _allowed = HtmlStringExtensions.UpdateAllowed(); var sw = new System.Diagnostics.Stopwatch(); sw.Start(); Hash thread = null; if (request.Address != "/") { thread = new Hash(request.Address.Split('/').Last()); if (thread.Invalid) { return new ErrorHandler(StatusCode.BadRequest, "Wrong hash format.").Handle(request); } } else { thread = _db.RootHash; } var sb = new StringBuilder(); AddHeader(sb); string s1 = ""; if (thread.Value != _db.RootHash.Value) { s1 = "<a href='#' onclick='history.go(-1)'>[Назад]</a>"; s1 += "<a href='#' onclick='location.reload()'>[Обновить]</a>"; if (!_expand) s1 += "<a href='#' onclick='window.location.href=window.location.toString().replace(\"thread\",\"expand\")'>[Развернуть]</a>"; else s1 += "<a href='#' onclick='window.location.href=window.location.toString().replace(\"expand\",\"thread\")'>[Свернуть]</a>"; } else { s1 = "<a href='#' onclick='location.reload()'>[Обновить]</a>"; } sb.Append(s1.ToDiv("", "")); NanoPost[] posts = null; /* if (!_expand) posts = _db.GetThreadPosts(thread).ExceptHidden(_db); else posts = _db.GetExpandedThreadPosts(thread).ExceptHidden(_db); */ if (!_expand) posts = _db.GetThreadPosts(thread); else posts = _db.GetExpandedThreadPosts(thread); bool first = true; if (!_expand) { posts = posts.OrderByDescending(p => p.NumberTag).ToArray(); } string postScript = ""; foreach (var sp in posts) { var p = sp; //string pMessage = p.Message; string pMessage = p.Message.Strip(true); var fmPattern = "\\[fm=.*\\]"; var music = Regex.Matches(pMessage, fmPattern); int musicNum = 0; foreach (var m in music) { musicNum += 1; var value = (m as Match).Value; var formula = value.Substring(4).TrimEnd(']').Replace(">", ">").Replace("<", "<").Replace("<grn>", "").Replace("</grn>", "").Replace(" ", " "). Replace("’", "'").Replace("“", "\"").Replace(";", ""); var strictFmPattern = "()t *0123456789abcdefxABCDEF|><!%:^&.-+/?=~"; bool invalid = formula.Length > 8192; if (!invalid) foreach (var ch in formula) { if (!strictFmPattern.Contains(ch)) { invalid = true; break; } } if (invalid) continue; var replacement = string.Format(@"<b>Фрактальная музыка:</b> <small><pre>{1}</pre></small><button id='mb{0}'>Сгенерировать</button> <audio style='visibility:hidden;' controls='false' id='au{0}'></audio>", sp.GetHash().Value + musicNum, formula); postScript += "document.getElementById('mb" + sp.GetHash().Value + musicNum + "').onclick = function() { addFractalMusic(function(t){return " + formula + ";}, 210*8000, 'au" + sp.GetHash().Value + musicNum + "');" + "this.parentNode.removeChild(this);" + "}\n"; pMessage = pMessage.Replace(value, replacement); } string numTag = (p.NumberTag == int.MaxValue ? "" : "<grn><sup>#" + p.GetHash().Value.ShortenHash() + "</sup></grn> "); bool hidden = false; if (_db.IsHidden(p.GetHash())) { hidden = true; } string handler = "/expand/"; bool corePost = false; if (p.GetHash().Value == NanoDB.RootHashValue || // root p.ReplyTo.Value == NanoDB.RootHashValue || // root p.GetHash().Value == NanoDB.CategoriesHashValue || // categories p.ReplyTo.Value == NanoDB.CategoriesHashValue) // categories { handler = "/thread/"; corePost = true; } if (_db.Get(p.ReplyTo) != null && (_db.Get(p.ReplyTo).ReplyTo.Value == NanoDB.CategoriesHashValue || _db.Get(p.ReplyTo).ReplyTo.Value == NanoDB.RootHashValue)) { corePost = true; } Func<NanoPost,string> addRefs = pst => { var children = _db.GetThreadPosts(pst.GetHash(), eraseDepth:false); var refs1 = "<br/><div><small>"; int line = 0; foreach (var ch in children) { if (ch.GetHash().Value != pst.GetHash().Value) { line += 1; refs1 += "<a href='#" + ch.GetHash().Value + "'><i>>>" + ch.GetHash().Value.ShortenHash() + "</i></a>"; if (line > 5) { line = 0; refs1 += "</br>"; } } } refs1 += "</small></div>"; return refs1; }; if (_expand && first && !p.GetHash().Zero && !p.ReplyTo.Zero) { string refs = ""; if (p.ReplyTo.Value != NanoDB.CategoriesHashValue && p.ReplyTo.Value != NanoDB.RootHashValue && _expand) { refs = addRefs(p); } sb.Append( ( (numTag + pMessage + refs).Replace("\n", "<br/>").ToDiv("postinner", p.GetHash().Value) + ("[Вверх]".ToRef((corePost ? "/thread/" : "/expand/") + p.ReplyTo.Value) + //("[В закладки]").ToRef("/bookmark/" + p.GetHash().Value) + ("<a onclick='show_reply(\""+p.GetHash().Value+"\")'>[Быстрый ответ]</a>")+("[Ответить]").ToRef("/reply/" + p.GetHash().Value)).ToDiv("", "") ).ToDiv("post", "")); first = false; continue; } first = false; int answers = _db.CountAnswers(p.GetHash()); string ans = "ответ"; int a = answers % 100; if (a == 0 || a % 10 == 0 || (a > 10 && a < 20)) ans += "ов"; else if (a % 10 >= 2 && a % 10 <= 4) ans += "а"; else if (a % 10 >= 5 && a % 10 <= 9) ans += "ов"; if (p.GetHash().Value == _db.RootHash.Value) { sb.Append( ( (@" Добро пожаловать на Наноборду! Это корневой нанопост. В целях тестирования на него можно было отвечать в предыдущих версиях. Это немного засорило Главную. Рекомендуется почистить её у себя вручную. Негласное правило: отвечать нужно на конкретное сообщение, а не просто ""в тред"", полагаясь на то, что сообщение выше вашего будет таким же и у других - порядок попадания нанопостов к другим участникам сложно предсказать. Создавать тред желательно в соответствующей категории." ).Strip().Replace("\n", "<br/>").ToDiv("postinner", p.GetHash().Value) + //(("[Ответить]").ToRef("/reply/" + p.GetHash().Value)).ToDiv("", "") + ("[Развернуть всё (осторожно!)]").ToRef("/expand/f682830a470200d738d32c69e6c2b8a4").ToDiv("", "") + ("[Категории]").ToRef("/thread/bdd4b5fc1b3a933367bc6830fef72a35").ToDiv("", "") ).ToDiv("post main", "")); } else { string refs = ""; if (p.ReplyTo.Value != NanoDB.CategoriesHashValue && p.ReplyTo.Value != NanoDB.RootHashValue && _expand) { refs = addRefs(p); } sb.Append( ( ((_expand?("<a href='#"+p.ReplyTo.Value+"'><i>>>"+p.ReplyTo.Value.ShortenHash()+"</i></a><br/>"):"") + numTag+pMessage+refs).Replace("\n", "<br/>").ToStyledDiv("postinner", p.GetHash().Value, hidden?"visibility:hidden;height:0px;":"") + ((answers > MinAnswers ? ("[" + answers + " " + ans + "]").ToRef(handler + p.GetHash().Value) : "") + (p.GetHash().Value != "bdd4b5fc1b3a933367bc6830fef72a35" ? ( (hidden?"[Вернуть]":"[Удалить]").ToButton("", "", @"var x = new XMLHttpRequest(); x.open('POST', '../hide/" + p.GetHash().Value + @"', true); x.send(''); var elem = document.getElementById('" + p.GetHash().Value + @"'); if (elem.style.visibility != 'hidden') { elem.style.visibility='hidden'; elem.style.height = '0px'; innerHTML = '[Вернуть]'; } else { elem.style.visibility='visible'; elem.style.height = '100%'; innerHTML = '[Удалить]'; } ")) : "") + //("[В закладки]").ToRef("/bookmark/" + p.GetHash().Value) + ("<a onclick='show_reply(\""+p.GetHash().Value+"\")'>[Быстрый ответ]</a>")+("[Ответить]").ToRef("/reply/" + p.GetHash().Value)).ToDiv("", "") ).ToStyledDiv("post", "", "position:relative;left:" + p.DepthTag * 20 + "px;")); } } sb.Append(s1.ToDiv("", "")); sw.Stop(); sb.Append("<div><br>места:"); var places = _places.Where(l => !l.StartsWith("#")).ToList(); places.ForEach(p => sb.Append(string.Format("<br><a target='_blank' href='{0}'>{0}</a>"+ "<a target='_blank' href='/del/{0}'>[-]</a>", p))); sb.Append("</div>"); AddFooter(sb, sw.ElapsedMilliseconds, _db); var result = sb.ToString(); /* if (!_expand) sb.Append("Развернуть".ToButton("", "", "window.location.href=window.location.toString().replace('thread','expand')").ToDiv("","")); else sb.Append("Обновить".ToButton("", "", "location.reload()").ToDiv("","")); */ return new NanoHttpResponse(StatusCode.Ok, result.AddVideo().AddReply().ToHtmlBody(FractalMusicScript + PostScript(postScript))); }
public NanoPost[] GetThreadPosts(Hash thread, bool eraseDepth = true) { if (!_threadPosts.ContainsKey(thread)) { if (_posts.ContainsKey(thread)) { return new NanoPost[] { _posts[thread] }; } else { return new NanoPost[0]; } } var list = new List<NanoPost>(); if (_posts.ContainsKey(thread)) { list.Add(_posts[thread]); } list.AddRange(_threadPosts[thread].ToArray().Sorted()); if (eraseDepth) list.ForEach(p => p.DepthTag = 0); return list.ToArray(); }
public int CountAnswersRecursive(Hash thread) { if (!_threadPosts.ContainsKey(thread)) return 0; int res = 0; var stack = new Stack<Hash>(); stack.Push(thread); while (stack.Count > 0) { var v = stack.Pop(); if (_threadPosts.ContainsKey(v)) { foreach (var p in _threadPosts[v]) { res += 1; stack.Push(p.GetHash()); } } } return res; }
public NanoPost[] GetExpandedThreadPosts(Hash thread, int depth = 0, List<NanoPost> list = null) { if (list == null) { list = new List<NanoPost>(); } if (depth == 0) { // clear depth foreach (var p in _posts) { p.Value.DepthTag = 0; } } if (!_threadPosts.ContainsKey(thread)) { if (_posts.ContainsKey(thread)) { _posts[thread].DepthTag = depth; list.Add(_posts[thread]); return new NanoPost[] { _posts[thread] }; } else { return new NanoPost[0]; } } if (depth == 0 && _posts.ContainsKey(thread)) { _posts[thread].DepthTag = depth; list.Add(_posts[thread]); } var tps = _threadPosts[thread].OrderBy(p => p.NumberTag).ToArray(); foreach (var tp in tps) { tp.DepthTag = depth + 1; list.Add(tp); GetExpandedThreadPosts(tp.GetHash(), depth + 1, list); } return list.Distinct().ToArray(); }
public int CountAnswers(Hash thread) { return CountAnswersRecursive(thread); //return _threadPosts.ContainsKey(thread) ? _threadPosts[thread].ToArray().ExceptHidden(this).Length : 0; }
public NanoPost Get(Hash hash) { if (!_posts.ContainsKey(hash)) { return null; } return _posts[hash]; }
public void Unhide(Hash hash) { if (!_hideList.Contains(hash.Value)) return; if (hash.Zero) return; if (hash.Value == RootHash.Value) return; _hideList.Remove(hash.Value); if (_onceList.Contains(hash.Value)) { _onceList.Remove(hash.Value); } }
public void Hide(Hash hash) { if (_hideList.Contains(hash.Value)) return; if (hash.Zero) return; if (hash.Value == RootHash.Value) return; _hideList.Add(hash.Value); }
public bool IsHidden(Hash hash) { return _hideList.Contains(hash.Value) || _onceList.Contains(hash.Value); }