{"action":"created","comment":{"url":"https://api.github.com/repos/ornicar/lila/pulls/comments/63849400","id":63849400,"diff_hunk":"@@ -0,0 +1,66 @@\n+package lila.forum\n+\n+import lila.common.Future\n+\n+/**\n+  * Notifier to inform users if they have been mentioned in a post\n+  *\n+  * @param messageApi Api for sending inbox messages\n+  */\n+final class MentionNotifier(messageApi: lila.message.Api) {\n+\n+  /**\n+    * Notify any users mentioned in a post that they have been mentioned\n+    *\n+    * @param post The post which may or may not mention users\n+    * @return\n+    */\n+  def notifyMentionedUsers(post: Post, topic: Topic): Fu[Unit] = {\n+\n+    post.userId match {\n+      case None => fuccess()\n+      case Some(author) =>\n+        val mentionedUsers = extractMentionedUsers(post)\n+        Future.applySequentially(mentionedUsers)(informOfMention(post, topic, _, author))\n+    }\n+  }\n+\n+  /**\n+    * Inform user that they have been mentioned by another user\n+    *\n+    * @param post          The post that mentions the user\n+    * @param topic         The topic of the post that mentions the user\n+    * @param mentionedUser The user that was mentioned\n+    * @param mentionedBy   The user that mentioned the user\n+    * @return\n+    */\n+  def informOfMention(post: Post, topic: Topic, mentionedUser: String, mentionedBy: String): Fu[Unit] = {\n+    val inboxNotificationMessage = lila.hub.actorApi.message.LichessThread(\n+      from = \"Lichess\",\n+      to = mentionedUser,\n+      subject = mentionedBy ++ \" mentioned you.\",\n+      message = mentionedBy ++ \" mentioned you in the following forum post: \" ++\n+        \"http://lichess.org/forum/\" ++ post.categId ++ \"/\" ++ topic.name ++ \"#\" ++ Integer.toString(post.number))\n+\n+    messageApi.lichessThread(inboxNotificationMessage)\n+  }\n+\n+  /**\n+    * Pull out any users mentioned in a post\n+    *\n+    * @param post The post which may or may not mention users\n+    * @return\n+    */\n+  def extractMentionedUsers(post: Post): List[String] = {\n+    val postText = post.text\n+\n+    postText match {\n+      case postText if postText.contains('@') =>\n+        val postWords = postText.split(' ')\n+        postWords.filter(_.startsWith(\"@\")).distinct.map(_.tail).toList\n+      case _ => List()\n+    }\n+\n+\n+  }\n+}","path":"modules/forum/src/main/MentionNotifier.scala","position":66,"original_position":66,"commit_id":"452e479dd6d3723b6f8be57e593bd8ed6a0fd4f6","original_commit_id":"452e479dd6d3723b6f8be57e593bd8ed6a0fd4f6","user":{"login":"ornicar","id":140370,"avatar_url":"https://avatars.githubusercontent.com/u/140370?v=3","gravatar_id":"","url":"https://api.github.com/users/ornicar","html_url":"https://github.com/ornicar","followers_url":"https://api.github.com/users/ornicar/followers","following_url":"https://api.github.com/users/ornicar/following{/other_user}","gists_url":"https://api.github.com/users/ornicar/gists{/gist_id}","starred_url":"https://api.github.com/users/ornicar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ornicar/subscriptions","organizations_url":"https://api.github.com/users/ornicar/orgs","repos_url":"https://api.github.com/users/ornicar/repos","events_url":"https://api.github.com/users/ornicar/events{/privacy}","received_events_url":"https://api.github.com/users/ornicar/received_events","type":"User","site_admin":false},"body":"newline!","created_at":"2016-05-19T09:41:33Z","updated_at":"2016-05-19T09:41:33Z","html_url":"https://github.com/ornicar/lila/pull/1885#discussion_r63849400","pull_request_url":"https://api.github.com/repos/ornicar/lila/pulls/1885","_links":{"self":{"href":"https://api.github.com/repos/ornicar/lila/pulls/comments/63849400"},"html":{"href":"https://github.com/ornicar/lila/pull/1885#discussion_r63849400"},"pull_request":{"href":"https://api.github.com/repos/ornicar/lila/pulls/1885"}}},"pull_request":{"url":"https://api.github.com/repos/ornicar/lila/pulls/1885","id":70614886,"html_url":"https://github.com/ornicar/lila/pull/1885","diff_url":"https://github.com/ornicar/lila/pull/1885.diff","patch_url":"https://github.com/ornicar/lila/pull/1885.patch","issue_url":"https://api.github.com/repos/ornicar/lila/issues/1885","number":1885,"state":"open","locked":false,"title":"Begin adding support for mentioning users on the site","user":{"login":"Happy0","id":1145180,"avatar_url":"https://avatars.githubusercontent.com/u/1145180?v=3","gravatar_id":"","url":"https://api.github.com/users/Happy0","html_url":"https://github.com/Happy0","followers_url":"https://api.github.com/users/Happy0/followers","following_url":"https://api.github.com/users/Happy0/following{/other_user}","gists_url":"https://api.github.com/users/Happy0/gists{/gist_id}","starred_url":"https://api.github.com/users/Happy0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Happy0/subscriptions","organizations_url":"https://api.github.com/users/Happy0/orgs","repos_url":"https://api.github.com/users/Happy0/repos","events_url":"https://api.github.com/users/Happy0/events{/privacy}","received_events_url":"https://api.github.com/users/Happy0/received_events","type":"User","site_admin":false},"body":"Not quite complete yet - opening a pull request for review / comments / to ask questions.\r\n\r\nThis pull request allows users to mention users on the site using '@' like in twitter and github (e.g. @ornicar.)\r\n\r\nThis pull request doesn't add autocomplete functionality to the client - I can either add that to this pull request or a future pull request.\r\n\r\nWhat I think needs considered before merging:\r\n\r\n1. Do we need to verify if a mentioned user exists before sending the message? Will it clog up mongodb if we send a message to a non-existent user? If so, is there a method somewhere in the codebase for checking that a user exists?\r\n\r\n2. Rather than doing 'mentionNotifier.notifyMentionedUsers' in the future chain for making a post, do we want to kick it off in a separate operation since it won't impact the success of the user's request?\r\n\r\n3. Can any improvements be made to the message that arrives in the user's inbox?\r\n\r\n4. We should probably allow users to ignore mentions. What granularity should we use? 'Ignore all mentions from anyone' or 'ignore mentions from this user'? Both? :P\r\n\r\nYou guys may have other comments :D\r\n","created_at":"2016-05-18T23:16:37Z","updated_at":"2016-05-19T09:41:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cf5176bbb9fda78a0aa8c2777ff1f2413d7567c2","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ornicar/lila/pulls/1885/commits","review_comments_url":"https://api.github.com/repos/ornicar/lila/pulls/1885/comments","review_comment_url":"https://api.github.com/repos/ornicar/lila/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ornicar/lila/issues/1885/comments","statuses_url":"https://api.github.com/repos/ornicar/lila/statuses/452e479dd6d3723b6f8be57e593bd8ed6a0fd4f6","head":{"label":"Happy0:mentions","ref":"mentions","sha":"452e479dd6d3723b6f8be57e593bd8ed6a0fd4f6","user":{"login":"Happy0","id":1145180,"avatar_url":"https://avatars.githubusercontent.com/u/1145180?v=3","gravatar_id":"","url":"https://api.github.com/users/Happy0","html_url":"https://github.com/Happy0","followers_url":"https://api.github.com/users/Happy0/followers","following_url":"https://api.github.com/users/Happy0/following{/other_user}","gists_url":"https://api.github.com/users/Happy0/gists{/gist_id}","starred_url":"https://api.github.com/users/Happy0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Happy0/subscriptions","organizations_url":"https://api.github.com/users/Happy0/orgs","repos_url":"https://api.github.com/users/Happy0/repos","events_url":"https://api.github.com/users/Happy0/events{/privacy}","received_events_url":"https://api.github.com/users/Happy0/received_events","type":"User","site_admin":false},"repo":{"id":27313218,"name":"lila","full_name":"Happy0/lila","owner":{"login":"Happy0","id":1145180,"avatar_url":"https://avatars.githubusercontent.com/u/1145180?v=3","gravatar_id":"","url":"https://api.github.com/users/Happy0","html_url":"https://github.com/Happy0","followers_url":"https://api.github.com/users/Happy0/followers","following_url":"https://api.github.com/users/Happy0/following{/other_user}","gists_url":"https://api.github.com/users/Happy0/gists{/gist_id}","starred_url":"https://api.github.com/users/Happy0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Happy0/subscriptions","organizations_url":"https://api.github.com/users/Happy0/orgs","repos_url":"https://api.github.com/users/Happy0/repos","events_url":"https://api.github.com/users/Happy0/events{/privacy}","received_events_url":"https://api.github.com/users/Happy0/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Happy0/lila","description":"Best chess web application, ever","fork":true,"url":"https://api.github.com/repos/Happy0/lila","forks_url":"https://api.github.com/repos/Happy0/lila/forks","keys_url":"https://api.github.com/repos/Happy0/lila/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Happy0/lila/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Happy0/lila/teams","hooks_url":"https://api.github.com/repos/Happy0/lila/hooks","issue_events_url":"https://api.github.com/repos/Happy0/lila/issues/events{/number}","events_url":"https://api.github.com/repos/Happy0/lila/events","assignees_url":"https://api.github.com/repos/Happy0/lila/assignees{/user}","branches_url":"https://api.github.com/repos/Happy0/lila/branches{/branch}","tags_url":"https://api.github.com/repos/Happy0/lila/tags","blobs_url":"https://api.github.com/repos/Happy0/lila/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Happy0/lila/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Happy0/lila/git/refs{/sha}","trees_url":"https://api.github.com/repos/Happy0/lila/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Happy0/lila/statuses/{sha}","languages_url":"https://api.github.com/repos/Happy0/lila/languages","stargazers_url":"https://api.github.com/repos/Happy0/lila/stargazers","contributors_url":"https://api.github.com/repos/Happy0/lila/contributors","subscribers_url":"https://api.github.com/repos/Happy0/lila/subscribers","subscription_url":"https://api.github.com/repos/Happy0/lila/subscription","commits_url":"https://api.github.com/repos/Happy0/lila/commits{/sha}","git_commits_url":"https://api.github.com/repos/Happy0/lila/git/commits{/sha}","comments_url":"https://api.github.com/repos/Happy0/lila/comments{/number}","issue_comment_url":"https://api.github.com/repos/Happy0/lila/issues/comments{/number}","contents_url":"https://api.github.com/repos/Happy0/lila/contents/{+path}","compare_url":"https://api.github.com/repos/Happy0/lila/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Happy0/lila/merges","archive_url":"https://api.github.com/repos/Happy0/lila/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Happy0/lila/downloads","issues_url":"https://api.github.com/repos/Happy0/lila/issues{/number}","pulls_url":"https://api.github.com/repos/Happy0/lila/pulls{/number}","milestones_url":"https://api.github.com/repos/Happy0/lila/milestones{/number}","notifications_url":"https://api.github.com/repos/Happy0/lila/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Happy0/lila/labels{/name}","releases_url":"https://api.github.com/repos/Happy0/lila/releases{/id}","deployments_url":"https://api.github.com/repos/Happy0/lila/deployments","created_at":"2014-11-29T19:51:10Z","updated_at":"2014-12-25T22:26:34Z","pushed_at":"2016-05-18T23:10:20Z","git_url":"git://github.com/Happy0/lila.git","ssh_url":"git@github.com:Happy0/lila.git","clone_url":"https://github.com/Happy0/lila.git","svn_url":"https://github.com/Happy0/lila","homepage":"http://lichess.org","size":112594,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ornicar:master","ref":"master","sha":"049edf1689e3fc9947aa29c7f170ae947887908d","user":{"login":"ornicar","id":140370,"avatar_url":"https://avatars.githubusercontent.com/u/140370?v=3","gravatar_id":"","url":"https://api.github.com/users/ornicar","html_url":"https://github.com/ornicar","followers_url":"https://api.github.com/users/ornicar/followers","following_url":"https://api.github.com/users/ornicar/following{/other_user}","gists_url":"https://api.github.com/users/ornicar/gists{/gist_id}","starred_url":"https://api.github.com/users/ornicar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ornicar/subscriptions","organizations_url":"https://api.github.com/users/ornicar/orgs","repos_url":"https://api.github.com/users/ornicar/repos","events_url":"https://api.github.com/users/ornicar/events{/privacy}","received_events_url":"https://api.github.com/users/ornicar/received_events","type":"User","site_admin":false},"repo":{"id":3507455,"name":"lila","full_name":"ornicar/lila","owner":{"login":"ornicar","id":140370,"avatar_url":"https://avatars.githubusercontent.com/u/140370?v=3","gravatar_id":"","url":"https://api.github.com/users/ornicar","html_url":"https://github.com/ornicar","followers_url":"https://api.github.com/users/ornicar/followers","following_url":"https://api.github.com/users/ornicar/following{/other_user}","gists_url":"https://api.github.com/users/ornicar/gists{/gist_id}","starred_url":"https://api.github.com/users/ornicar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ornicar/subscriptions","organizations_url":"https://api.github.com/users/ornicar/orgs","repos_url":"https://api.github.com/users/ornicar/repos","events_url":"https://api.github.com/users/ornicar/events{/privacy}","received_events_url":"https://api.github.com/users/ornicar/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ornicar/lila","description":"The forever free, adless and open source chess server.","fork":false,"url":"https://api.github.com/repos/ornicar/lila","forks_url":"https://api.github.com/repos/ornicar/lila/forks","keys_url":"https://api.github.com/repos/ornicar/lila/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ornicar/lila/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ornicar/lila/teams","hooks_url":"https://api.github.com/repos/ornicar/lila/hooks","issue_events_url":"https://api.github.com/repos/ornicar/lila/issues/events{/number}","events_url":"https://api.github.com/repos/ornicar/lila/events","assignees_url":"https://api.github.com/repos/ornicar/lila/assignees{/user}","branches_url":"https://api.github.com/repos/ornicar/lila/branches{/branch}","tags_url":"https://api.github.com/repos/ornicar/lila/tags","blobs_url":"https://api.github.com/repos/ornicar/lila/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ornicar/lila/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ornicar/lila/git/refs{/sha}","trees_url":"https://api.github.com/repos/ornicar/lila/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ornicar/lila/statuses/{sha}","languages_url":"https://api.github.com/repos/ornicar/lila/languages","stargazers_url":"https://api.github.com/repos/ornicar/lila/stargazers","contributors_url":"https://api.github.com/repos/ornicar/lila/contributors","subscribers_url":"https://api.github.com/repos/ornicar/lila/subscribers","subscription_url":"https://api.github.com/repos/ornicar/lila/subscription","commits_url":"https://api.github.com/repos/ornicar/lila/commits{/sha}","git_commits_url":"https://api.github.com/repos/ornicar/lila/git/commits{/sha}","comments_url":"https://api.github.com/repos/ornicar/lila/comments{/number}","issue_comment_url":"https://api.github.com/repos/ornicar/lila/issues/comments{/number}","contents_url":"https://api.github.com/repos/ornicar/lila/contents/{+path}","compare_url":"https://api.github.com/repos/ornicar/lila/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ornicar/lila/merges","archive_url":"https://api.github.com/repos/ornicar/lila/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ornicar/lila/downloads","issues_url":"https://api.github.com/repos/ornicar/lila/issues{/number}","pulls_url":"https://api.github.com/repos/ornicar/lila/pulls{/number}","milestones_url":"https://api.github.com/repos/ornicar/lila/milestones{/number}","notifications_url":"https://api.github.com/repos/ornicar/lila/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ornicar/lila/labels{/name}","releases_url":"https://api.github.com/repos/ornicar/lila/releases{/id}","deployments_url":"https://api.github.com/repos/ornicar/lila/deployments","created_at":"2012-02-21T19:46:55Z","updated_at":"2016-05-19T06:42:56Z","pushed_at":"2016-05-19T09:36:08Z","git_url":"git://github.com/ornicar/lila.git","ssh_url":"git@github.com:ornicar/lila.git","clone_url":"https://github.com/ornicar/lila.git","svn_url":"https://github.com/ornicar/lila","homepage":"http://lichess.org","size":137534,"stargazers_count":2012,"watchers_count":2012,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":344,"mirror_url":null,"open_issues_count":287,"forks":344,"open_issues":287,"watchers":2012,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ornicar/lila/pulls/1885"},"html":{"href":"https://github.com/ornicar/lila/pull/1885"},"issue":{"href":"https://api.github.com/repos/ornicar/lila/issues/1885"},"comments":{"href":"https://api.github.com/repos/ornicar/lila/issues/1885/comments"},"review_comments":{"href":"https://api.github.com/repos/ornicar/lila/pulls/1885/comments"},"review_comment":{"href":"https://api.github.com/repos/ornicar/lila/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ornicar/lila/pulls/1885/commits"},"statuses":{"href":"https://api.github.com/repos/ornicar/lila/statuses/452e479dd6d3723b6f8be57e593bd8ed6a0fd4f6"}}}}