{"action":"created","comment":{"url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/comments/25535541","id":25535541,"diff_hunk":"@@ -0,0 +1,268 @@\n+# -*- coding: utf-8 -*-\n+#\n+# Copyright (C) 2014 Harvard\n+#\n+# Authors:\n+#          Xavier Antoviaque <xavier@antoviaque.org>\n+#\n+# This software's license gives you freedom; you can copy, convey,\n+# propagate, redistribute and/or modify this program under the terms of\n+# the GNU Affero General Public License (AGPL) as published by the Free\n+# Software Foundation (FSF), either version 3 of the License, or (at your\n+# option) any later version of the AGPL published by the FSF.\n+#\n+# This program is distributed in the hope that it will be useful, but\n+# WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero\n+# General Public License for more details.\n+#\n+# You should have received a copy of the GNU Affero General Public License\n+# along with this program in a file in the toplevel directory called\n+# \"AGPLv3\".  If not, see <http://www.gnu.org/licenses/>.\n+#\n+\n+# Imports ###########################################################\n+\n+import logging\n+from lazy import lazy\n+\n+from mentoring.models import Answer\n+\n+from xblock.core import XBlock\n+from xblock.fields import Scope, Float, Integer, String\n+from xblock.fragment import Fragment\n+from xblock.validation import ValidationMessage\n+from xblockutils.resources import ResourceLoader\n+from xblockutils.studio_editable import StudioEditableXBlockMixin\n+from .step import StepMixin\n+import uuid\n+\n+\n+# Globals ###########################################################\n+\n+log = logging.getLogger(__name__)\n+loader = ResourceLoader(__name__)\n+\n+# Classes ###########################################################\n+\n+\n+class AnswerMixin(object):\n+    \"\"\"\n+    Mixin to give an XBlock the ability to read/write data to the Answers DB table.\n+    \"\"\"\n+    def _get_course_id(self):\n+        \"\"\" Get a course ID if available \"\"\"\n+        return getattr(self.runtime, 'course_id', 'all')\n+\n+    def _get_student_id(self):\n+        \"\"\" Get student anonymous ID or normal ID \"\"\"\n+        try:\n+            return self.runtime.anonymous_student_id\n+        except AttributeError:\n+            return self.scope_ids.user_id\n+\n+    def get_model_object(self, name=None):\n+        \"\"\"\n+        Fetches the Answer model object for the answer named `name`\n+        \"\"\"\n+        # By default, get the model object for the current answer's name\n+        if not name:\n+            name = self.name\n+        # Consistency check - we should have a name by now\n+        if not name:\n+            raise ValueError('AnswerBlock.name field need to be set to a non-null/empty value')\n+\n+        student_id = self._get_student_id()\n+        course_id = self._get_course_id()\n+\n+        answer_data, _ = Answer.objects.get_or_create(\n+            student_id=student_id,\n+            course_id=course_id,\n+            name=name,\n+        )\n+        return answer_data\n+\n+    def validate_field_data(self, validation, data):\n+        \"\"\"\n+        Validate this block's field data.\n+        \"\"\"\n+        super(AnswerMixin, self).validate_field_data(validation, data)\n+\n+        def add_error(msg):\n+            validation.add(ValidationMessage(ValidationMessage.ERROR, msg))\n+\n+        if not data.name:\n+            add_error(u\"A Question ID is required.\")\n+\n+\n+class AnswerBlock(AnswerMixin, StepMixin, StudioEditableXBlockMixin, XBlock):\n+    \"\"\"\n+    A field where the student enters an answer\n+\n+    Must be included as a child of a mentoring block. Answers are persisted as django model instances\n+    to make them searchable and referenceable across xblocks.\n+    \"\"\"\n+    name = String(\n+        display_name=\"Question ID (name)\",","path":"mentoring/components/answer.py","position":106,"original_position":106,"commit_id":"adf8de62d746ea5d796f2017e990b361ce78b77a","original_commit_id":"adf8de62d746ea5d796f2017e990b361ce78b77a","user":{"login":"bradenmacdonald","id":945577,"avatar_url":"https://avatars.githubusercontent.com/u/945577?v=3","gravatar_id":"","url":"https://api.github.com/users/bradenmacdonald","html_url":"https://github.com/bradenmacdonald","followers_url":"https://api.github.com/users/bradenmacdonald/followers","following_url":"https://api.github.com/users/bradenmacdonald/following{/other_user}","gists_url":"https://api.github.com/users/bradenmacdonald/gists{/gist_id}","starred_url":"https://api.github.com/users/bradenmacdonald/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradenmacdonald/subscriptions","organizations_url":"https://api.github.com/users/bradenmacdonald/orgs","repos_url":"https://api.github.com/users/bradenmacdonald/repos","events_url":"https://api.github.com/users/bradenmacdonald/events{/privacy}","received_events_url":"https://api.github.com/users/bradenmacdonald/received_events","type":"User","site_admin":false},"body":"It is sort of being auto-generated - see `@classmethod def get_template` below in this class. Basically in Studio, it will generate a new ID as part of the \"Add a New Block\" button process. In Workbench/XML you must manually specify an ID.","created_at":"2015-02-27T20:15:56Z","updated_at":"2015-02-27T20:15:56Z","html_url":"https://github.com/open-craft/xblock-mentoring/pull/4#discussion_r25535541","pull_request_url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4","_links":{"self":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/comments/25535541"},"html":{"href":"https://github.com/open-craft/xblock-mentoring/pull/4#discussion_r25535541"},"pull_request":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4"}}},"pull_request":{"url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4","id":28813760,"html_url":"https://github.com/open-craft/xblock-mentoring/pull/4","diff_url":"https://github.com/open-craft/xblock-mentoring/pull/4.diff","patch_url":"https://github.com/open-craft/xblock-mentoring/pull/4.patch","issue_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/4","number":4,"state":"open","locked":false,"title":"Unification of forks & conversion to real children","user":{"login":"antoviaque","id":514483,"avatar_url":"https://avatars.githubusercontent.com/u/514483?v=3","gravatar_id":"","url":"https://api.github.com/users/antoviaque","html_url":"https://github.com/antoviaque","followers_url":"https://api.github.com/users/antoviaque/followers","following_url":"https://api.github.com/users/antoviaque/following{/other_user}","gists_url":"https://api.github.com/users/antoviaque/gists{/gist_id}","starred_url":"https://api.github.com/users/antoviaque/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/antoviaque/subscriptions","organizations_url":"https://api.github.com/users/antoviaque/orgs","repos_url":"https://api.github.com/users/antoviaque/repos","events_url":"https://api.github.com/users/antoviaque/events{/privacy}","received_events_url":"https://api.github.com/users/antoviaque/received_events","type":"User","site_admin":false},"body":"Note that this PR isn't meant to be merged, it just serves to show the difference with what is on edx.org. Note that the two have slightly diverged, due to backports of features. We would likely switch the requirements used on edx.org to use the current repository's master rather than merging.\r\n\r\nSee https://openedx.atlassian.net/browse/OSPR-419\r\n\r\nSandbox: LMS: http://sandbox.opencraft.com/ - CMS: http://sandbox.opencraft.com:18010/","created_at":"2015-02-06T14:53:17Z","updated_at":"2015-02-27T20:15:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4/commits","review_comments_url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4/comments","review_comment_url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/comments{/number}","comments_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/4/comments","statuses_url":"https://api.github.com/repos/open-craft/xblock-mentoring/statuses/adf8de62d746ea5d796f2017e990b361ce78b77a","head":{"label":"open-craft:master","ref":"master","sha":"adf8de62d746ea5d796f2017e990b361ce78b77a","user":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"repo":{"id":29684458,"name":"xblock-mentoring","full_name":"open-craft/xblock-mentoring","owner":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-craft/xblock-mentoring","description":"Mentoring XBlock for edX","fork":true,"url":"https://api.github.com/repos/open-craft/xblock-mentoring","forks_url":"https://api.github.com/repos/open-craft/xblock-mentoring/forks","keys_url":"https://api.github.com/repos/open-craft/xblock-mentoring/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-craft/xblock-mentoring/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-craft/xblock-mentoring/teams","hooks_url":"https://api.github.com/repos/open-craft/xblock-mentoring/hooks","issue_events_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/events{/number}","events_url":"https://api.github.com/repos/open-craft/xblock-mentoring/events","assignees_url":"https://api.github.com/repos/open-craft/xblock-mentoring/assignees{/user}","branches_url":"https://api.github.com/repos/open-craft/xblock-mentoring/branches{/branch}","tags_url":"https://api.github.com/repos/open-craft/xblock-mentoring/tags","blobs_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-craft/xblock-mentoring/statuses/{sha}","languages_url":"https://api.github.com/repos/open-craft/xblock-mentoring/languages","stargazers_url":"https://api.github.com/repos/open-craft/xblock-mentoring/stargazers","contributors_url":"https://api.github.com/repos/open-craft/xblock-mentoring/contributors","subscribers_url":"https://api.github.com/repos/open-craft/xblock-mentoring/subscribers","subscription_url":"https://api.github.com/repos/open-craft/xblock-mentoring/subscription","commits_url":"https://api.github.com/repos/open-craft/xblock-mentoring/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-craft/xblock-mentoring/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-craft/xblock-mentoring/contents/{+path}","compare_url":"https://api.github.com/repos/open-craft/xblock-mentoring/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-craft/xblock-mentoring/merges","archive_url":"https://api.github.com/repos/open-craft/xblock-mentoring/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-craft/xblock-mentoring/downloads","issues_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues{/number}","pulls_url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls{/number}","milestones_url":"https://api.github.com/repos/open-craft/xblock-mentoring/milestones{/number}","notifications_url":"https://api.github.com/repos/open-craft/xblock-mentoring/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-craft/xblock-mentoring/labels{/name}","releases_url":"https://api.github.com/repos/open-craft/xblock-mentoring/releases{/id}","created_at":"2015-01-22T15:11:16Z","updated_at":"2015-02-27T05:59:11Z","pushed_at":"2015-02-27T15:26:45Z","git_url":"git://github.com/open-craft/xblock-mentoring.git","ssh_url":"git@github.com:open-craft/xblock-mentoring.git","clone_url":"https://github.com/open-craft/xblock-mentoring.git","svn_url":"https://github.com/open-craft/xblock-mentoring","homepage":null,"size":1947,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":0,"default_branch":"master"}},"base":{"label":"open-craft:gsehub","ref":"gsehub","sha":"fd472edde6ea1455333a955d7b1942378ae68bd8","user":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"repo":{"id":29684458,"name":"xblock-mentoring","full_name":"open-craft/xblock-mentoring","owner":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-craft/xblock-mentoring","description":"Mentoring XBlock for edX","fork":true,"url":"https://api.github.com/repos/open-craft/xblock-mentoring","forks_url":"https://api.github.com/repos/open-craft/xblock-mentoring/forks","keys_url":"https://api.github.com/repos/open-craft/xblock-mentoring/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-craft/xblock-mentoring/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-craft/xblock-mentoring/teams","hooks_url":"https://api.github.com/repos/open-craft/xblock-mentoring/hooks","issue_events_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/events{/number}","events_url":"https://api.github.com/repos/open-craft/xblock-mentoring/events","assignees_url":"https://api.github.com/repos/open-craft/xblock-mentoring/assignees{/user}","branches_url":"https://api.github.com/repos/open-craft/xblock-mentoring/branches{/branch}","tags_url":"https://api.github.com/repos/open-craft/xblock-mentoring/tags","blobs_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-craft/xblock-mentoring/statuses/{sha}","languages_url":"https://api.github.com/repos/open-craft/xblock-mentoring/languages","stargazers_url":"https://api.github.com/repos/open-craft/xblock-mentoring/stargazers","contributors_url":"https://api.github.com/repos/open-craft/xblock-mentoring/contributors","subscribers_url":"https://api.github.com/repos/open-craft/xblock-mentoring/subscribers","subscription_url":"https://api.github.com/repos/open-craft/xblock-mentoring/subscription","commits_url":"https://api.github.com/repos/open-craft/xblock-mentoring/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-craft/xblock-mentoring/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-craft/xblock-mentoring/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-craft/xblock-mentoring/contents/{+path}","compare_url":"https://api.github.com/repos/open-craft/xblock-mentoring/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-craft/xblock-mentoring/merges","archive_url":"https://api.github.com/repos/open-craft/xblock-mentoring/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-craft/xblock-mentoring/downloads","issues_url":"https://api.github.com/repos/open-craft/xblock-mentoring/issues{/number}","pulls_url":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls{/number}","milestones_url":"https://api.github.com/repos/open-craft/xblock-mentoring/milestones{/number}","notifications_url":"https://api.github.com/repos/open-craft/xblock-mentoring/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-craft/xblock-mentoring/labels{/name}","releases_url":"https://api.github.com/repos/open-craft/xblock-mentoring/releases{/id}","created_at":"2015-01-22T15:11:16Z","updated_at":"2015-02-27T05:59:11Z","pushed_at":"2015-02-27T15:26:45Z","git_url":"git://github.com/open-craft/xblock-mentoring.git","ssh_url":"git@github.com:open-craft/xblock-mentoring.git","clone_url":"https://github.com/open-craft/xblock-mentoring.git","svn_url":"https://github.com/open-craft/xblock-mentoring","homepage":null,"size":1947,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4"},"html":{"href":"https://github.com/open-craft/xblock-mentoring/pull/4"},"issue":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/4"},"comments":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/issues/4/comments"},"review_comments":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4/comments"},"review_comment":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/pulls/4/commits"},"statuses":{"href":"https://api.github.com/repos/open-craft/xblock-mentoring/statuses/adf8de62d746ea5d796f2017e990b361ce78b77a"}}}}