{"id":20722472,"url":"https://github.com/toomanybees/topicdemo","last_synced_at":"2026-05-25T23:35:40.866Z","repository":{"id":12520006,"uuid":"15189822","full_name":"TooManyBees/TopicDemo","owner":"TooManyBees","description":"Article/Discussion/Comment system that separates offtopic threads into new discussions","archived":false,"fork":false,"pushed_at":"2013-12-16T03:57:57.000Z","size":344,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-17T23:15:27.902Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TooManyBees.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-12-14T17:47:13.000Z","updated_at":"2013-12-16T03:57:58.000Z","dependencies_parsed_at":"2022-09-10T22:31:36.335Z","dependency_job_id":null,"html_url":"https://github.com/TooManyBees/TopicDemo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TooManyBees%2FTopicDemo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TooManyBees%2FTopicDemo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TooManyBees%2FTopicDemo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TooManyBees%2FTopicDemo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TooManyBees","download_url":"https://codeload.github.com/TooManyBees/TopicDemo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242996847,"owners_count":20219028,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T03:35:59.665Z","updated_at":"2025-12-12T07:58:43.049Z","avatar_url":"https://github.com/TooManyBees.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TopicDemo\n\nA discussion system that automatically tries to detect off-topic comment threads, and split them off into new discussions.\n\n## The gist\n\nIt's a basic Article -\u003e Discussion -\u003e Comment system. Each article begins with a single default discussion, which comments can be posted to. They can also be voted positive or negative, and if a string of comments get enough negative votes, then the entire tree of comments will be moved to a new discussion.\n\nRequests to the server are made via Ajax, while updates are received through a web socket (using [Faye Websockets](https://github.com/faye/faye-websocket-ruby)).\n\n## Implementation\n\nMethods of note:\n\n`Discussion#find_children_of(comment)` retrieves all comments of discussion and returns only those descended from `comment`.\n\n`Comment#exceeds_negative_threshold?` finds the average rating of itself and all its descendant comments, and returns whether or not it's worse than a predetermined value. Always returns false if there are fewer than 5 child comments.\n\n`Comment#find_source_of_negativity` traverses up the comment tree to return the highest comment in an unbroken string of negatively rated comments. (This could just return self.)\n\n`Comment#form_new_discussion(options)` forms a new discussion. The discussion is marked as having been branched off of the comment's original discussion, and the comment and all its descendants are moved into it. If `options` contains `:hide =\u003e true`, then the new discussion will be greyed out wherever it's linked.\n\nEach time a comment is updated to change its rating, if its rating is below 0 the controller starts to check of the presence of a negative thread. First, it calls `find_source_of_negativity` to find the root of the possible thread. Then given that root, it calls `exceeds_negative_threshold?` to see if the subthread is bad enough to branch off. If so, the root receives `form_new_discussion(hide: true)` which moves it and its descendents away from the current discussion.\n\n## Testing\n\nLive demo is at https://intense-tor-5737.herokuapp.com/\n\nThere's a button on the root page called `Generate demo article`. It will seed a new article with a bunch of off-topic comments. A single down-vote on any of the negative rated comments will be enough to trip the detection method and push them into a parallel discussion.\n\n## Things that could be nice to do\n\nThere's a lot of db crawling to check the rating of child and parent comments. A little Redis or Memcached here and there would be the next thing to add, if the system is to scale.\n\nThe Discussion model has methods for banishing or promoting comments and their descendants (promotion being the same as \"banish\" but without graying out its link), so an admin option to manually choose which threads to branch off would be useful.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoomanybees%2Ftopicdemo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoomanybees%2Ftopicdemo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoomanybees%2Ftopicdemo/lists"}