{"action":"created","comment":{"url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/comments/24604683","id":24604683,"diff_hunk":"@@ -264,15 +283,128 @@ def assign_submission(backup_id, submit):\n         subm.put()\n         subm.mark_as_final()\n \n-def parse_date(date):\n-    # TODO Describe what date translation is happening here. Probably needs\n-    # a rewrite to handle daylight savings and work with other time zones.\n-    try:\n-        date = datetime.datetime.strptime(\n-            date, app.config[\"GAE_DATETIME_FORMAT\"])\n-    except ValueError:\n-        date = datetime.datetime.strptime(\n-            date, \"%Y-%m-%d %H:%M:%S\")\n+def sort_by_assignment(key_func, entries):\n+    entries = sorted(entries, key=key_func)\n+    return itertools.groupby(entries, key_func)\n \n-    delta = datetime.timedelta(hours=7)\n-    return datetime.datetime.combine(date.date(), date.time()) + delta\n+@ndb.toplevel\n+def merge_user(user_key, dup_user_key):\n+    \"\"\"\n+    Merges |dup_user| into |user|.\n+    \"\"\"\n+    if isinstance(user_key, ModelProxy.Base):\n+        user = user_key\n+        user_key = user_key.key\n+        get_user = lambda: dup_user\n+    else:\n+        user = user_key.get_async()\n+        def get_user():\n+            if isinstance(user, ndb.Future):\n+                user = user.get_result()\n+            return user\n+\n+    if isinstance(dup_user_key, ModelProxy.Base):\n+        dup_user = dup_user_key\n+        get_dup_user = lambda: dup_user\n+        dup_user_key = dup_user_key.key\n+    else:\n+        dup_user = dup_user_key.get_async()\n+        def get_dup_user():\n+            if isinstance(dup_user, ndb.Future):\n+                dup_user = dup_user.get_result()\n+            return dup_user\n+\n+    # Leave all groups\n+    G = ModelProxy.Group\n+    groups = G.query(ndb.OR(\n+        G.member == dup_user_key,\n+        G.invited == dup_user_key)).fetch()\n+    for group in groups:\n+        group.exit(dup_user_key)\n+\n+    # Re-submit submissions\n+    S = ModelProxy.Submission\n+    subms = S.query(S.submitter == dup_user_key).fetch()\n+    for subm in subms:\n+        subm.resubmit(user_key)\n+\n+    dup_user = get_dup_user()\n+    # Change email\n+    # Right now, I just append the hash of their key, which should be\n+    # something they can't guess... Maybe make it more secure??","path":"server/app/utils.py","position":103,"original_position":103,"commit_id":"23f53a87733822bfeb84ee028de5d532ea26404a","original_commit_id":"23f53a87733822bfeb84ee028de5d532ea26404a","user":{"login":"moowiz","id":1504248,"avatar_url":"https://avatars.githubusercontent.com/u/1504248?v=3","gravatar_id":"","url":"https://api.github.com/users/moowiz","html_url":"https://github.com/moowiz","followers_url":"https://api.github.com/users/moowiz/followers","following_url":"https://api.github.com/users/moowiz/following{/other_user}","gists_url":"https://api.github.com/users/moowiz/gists{/gist_id}","starred_url":"https://api.github.com/users/moowiz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/moowiz/subscriptions","organizations_url":"https://api.github.com/users/moowiz/orgs","repos_url":"https://api.github.com/users/moowiz/repos","events_url":"https://api.github.com/users/moowiz/events{/privacy}","received_events_url":"https://api.github.com/users/moowiz/received_events","type":"User","site_admin":false},"body":"Good idea!","created_at":"2015-02-12T18:35:18Z","updated_at":"2015-02-12T18:35:18Z","html_url":"https://github.com/Cal-CS-61A-Staff/ok/pull/374#discussion_r24604683","pull_request_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374","_links":{"self":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/comments/24604683"},"html":{"href":"https://github.com/Cal-CS-61A-Staff/ok/pull/374#discussion_r24604683"},"pull_request":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374"}}},"pull_request":{"url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374","id":29197987,"html_url":"https://github.com/Cal-CS-61A-Staff/ok/pull/374","diff_url":"https://github.com/Cal-CS-61A-Staff/ok/pull/374.diff","patch_url":"https://github.com/Cal-CS-61A-Staff/ok/pull/374.patch","issue_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/374","number":374,"state":"open","locked":false,"title":"Adds user merging.","user":{"login":"moowiz","id":1504248,"avatar_url":"https://avatars.githubusercontent.com/u/1504248?v=3","gravatar_id":"","url":"https://api.github.com/users/moowiz","html_url":"https://github.com/moowiz","followers_url":"https://api.github.com/users/moowiz/followers","following_url":"https://api.github.com/users/moowiz/following{/other_user}","gists_url":"https://api.github.com/users/moowiz/gists{/gist_id}","starred_url":"https://api.github.com/users/moowiz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/moowiz/subscriptions","organizations_url":"https://api.github.com/users/moowiz/orgs","repos_url":"https://api.github.com/users/moowiz/repos","events_url":"https://api.github.com/users/moowiz/events{/privacy}","received_events_url":"https://api.github.com/users/moowiz/received_events","type":"User","site_admin":false},"body":"Also adds some tentative uniqueness checks.","created_at":"2015-02-12T17:20:41Z","updated_at":"2015-02-12T18:35:18Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e57151bce0a33b7acc025a380996f80e81912459","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374/commits","review_comments_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374/comments","review_comment_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/comments/{number}","comments_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/374/comments","statuses_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/statuses/23f53a87733822bfeb84ee028de5d532ea26404a","head":{"label":"Cal-CS-61A-Staff:enhancement/moowiz/user_merging","ref":"enhancement/moowiz/user_merging","sha":"23f53a87733822bfeb84ee028de5d532ea26404a","user":{"login":"Cal-CS-61A-Staff","id":7565272,"avatar_url":"https://avatars.githubusercontent.com/u/7565272?v=3","gravatar_id":"","url":"https://api.github.com/users/Cal-CS-61A-Staff","html_url":"https://github.com/Cal-CS-61A-Staff","followers_url":"https://api.github.com/users/Cal-CS-61A-Staff/followers","following_url":"https://api.github.com/users/Cal-CS-61A-Staff/following{/other_user}","gists_url":"https://api.github.com/users/Cal-CS-61A-Staff/gists{/gist_id}","starred_url":"https://api.github.com/users/Cal-CS-61A-Staff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cal-CS-61A-Staff/subscriptions","organizations_url":"https://api.github.com/users/Cal-CS-61A-Staff/orgs","repos_url":"https://api.github.com/users/Cal-CS-61A-Staff/repos","events_url":"https://api.github.com/users/Cal-CS-61A-Staff/events{/privacy}","received_events_url":"https://api.github.com/users/Cal-CS-61A-Staff/received_events","type":"Organization","site_admin":false},"repo":{"id":19992691,"name":"ok","full_name":"Cal-CS-61A-Staff/ok","owner":{"login":"Cal-CS-61A-Staff","id":7565272,"avatar_url":"https://avatars.githubusercontent.com/u/7565272?v=3","gravatar_id":"","url":"https://api.github.com/users/Cal-CS-61A-Staff","html_url":"https://github.com/Cal-CS-61A-Staff","followers_url":"https://api.github.com/users/Cal-CS-61A-Staff/followers","following_url":"https://api.github.com/users/Cal-CS-61A-Staff/following{/other_user}","gists_url":"https://api.github.com/users/Cal-CS-61A-Staff/gists{/gist_id}","starred_url":"https://api.github.com/users/Cal-CS-61A-Staff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cal-CS-61A-Staff/subscriptions","organizations_url":"https://api.github.com/users/Cal-CS-61A-Staff/orgs","repos_url":"https://api.github.com/users/Cal-CS-61A-Staff/repos","events_url":"https://api.github.com/users/Cal-CS-61A-Staff/events{/privacy}","received_events_url":"https://api.github.com/users/Cal-CS-61A-Staff/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Cal-CS-61A-Staff/ok","description":"ok.py supports programming projects by running tests, tracking progress, and assisting in debugging.","fork":false,"url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok","forks_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/forks","keys_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/teams","hooks_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/hooks","issue_events_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/events{/number}","events_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/events","assignees_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/assignees{/user}","branches_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/branches{/branch}","tags_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/tags","blobs_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/refs{/sha}","trees_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/statuses/{sha}","languages_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/languages","stargazers_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/stargazers","contributors_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/contributors","subscribers_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/subscribers","subscription_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/subscription","commits_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/commits{/sha}","git_commits_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/commits{/sha}","comments_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/comments{/number}","issue_comment_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/comments/{number}","contents_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/contents/{+path}","compare_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/merges","archive_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/downloads","issues_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues{/number}","pulls_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls{/number}","milestones_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/milestones{/number}","notifications_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/labels{/name}","releases_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/releases{/id}","created_at":"2014-05-20T18:36:23Z","updated_at":"2015-02-12T10:04:59Z","pushed_at":"2015-02-12T17:20:03Z","git_url":"git://github.com/Cal-CS-61A-Staff/ok.git","ssh_url":"git@github.com:Cal-CS-61A-Staff/ok.git","clone_url":"https://github.com/Cal-CS-61A-Staff/ok.git","svn_url":"https://github.com/Cal-CS-61A-Staff/ok","homepage":null,"size":12695,"stargazers_count":9,"watchers_count":9,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"open_issues_count":56,"forks":3,"open_issues":56,"watchers":9,"default_branch":"master"}},"base":{"label":"Cal-CS-61A-Staff:master","ref":"master","sha":"16dbc99d7a5bc196bfa7cb0db75449a227beebaf","user":{"login":"Cal-CS-61A-Staff","id":7565272,"avatar_url":"https://avatars.githubusercontent.com/u/7565272?v=3","gravatar_id":"","url":"https://api.github.com/users/Cal-CS-61A-Staff","html_url":"https://github.com/Cal-CS-61A-Staff","followers_url":"https://api.github.com/users/Cal-CS-61A-Staff/followers","following_url":"https://api.github.com/users/Cal-CS-61A-Staff/following{/other_user}","gists_url":"https://api.github.com/users/Cal-CS-61A-Staff/gists{/gist_id}","starred_url":"https://api.github.com/users/Cal-CS-61A-Staff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cal-CS-61A-Staff/subscriptions","organizations_url":"https://api.github.com/users/Cal-CS-61A-Staff/orgs","repos_url":"https://api.github.com/users/Cal-CS-61A-Staff/repos","events_url":"https://api.github.com/users/Cal-CS-61A-Staff/events{/privacy}","received_events_url":"https://api.github.com/users/Cal-CS-61A-Staff/received_events","type":"Organization","site_admin":false},"repo":{"id":19992691,"name":"ok","full_name":"Cal-CS-61A-Staff/ok","owner":{"login":"Cal-CS-61A-Staff","id":7565272,"avatar_url":"https://avatars.githubusercontent.com/u/7565272?v=3","gravatar_id":"","url":"https://api.github.com/users/Cal-CS-61A-Staff","html_url":"https://github.com/Cal-CS-61A-Staff","followers_url":"https://api.github.com/users/Cal-CS-61A-Staff/followers","following_url":"https://api.github.com/users/Cal-CS-61A-Staff/following{/other_user}","gists_url":"https://api.github.com/users/Cal-CS-61A-Staff/gists{/gist_id}","starred_url":"https://api.github.com/users/Cal-CS-61A-Staff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cal-CS-61A-Staff/subscriptions","organizations_url":"https://api.github.com/users/Cal-CS-61A-Staff/orgs","repos_url":"https://api.github.com/users/Cal-CS-61A-Staff/repos","events_url":"https://api.github.com/users/Cal-CS-61A-Staff/events{/privacy}","received_events_url":"https://api.github.com/users/Cal-CS-61A-Staff/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Cal-CS-61A-Staff/ok","description":"ok.py supports programming projects by running tests, tracking progress, and assisting in debugging.","fork":false,"url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok","forks_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/forks","keys_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/teams","hooks_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/hooks","issue_events_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/events{/number}","events_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/events","assignees_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/assignees{/user}","branches_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/branches{/branch}","tags_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/tags","blobs_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/refs{/sha}","trees_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/statuses/{sha}","languages_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/languages","stargazers_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/stargazers","contributors_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/contributors","subscribers_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/subscribers","subscription_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/subscription","commits_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/commits{/sha}","git_commits_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/git/commits{/sha}","comments_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/comments{/number}","issue_comment_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/comments/{number}","contents_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/contents/{+path}","compare_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/merges","archive_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/downloads","issues_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues{/number}","pulls_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls{/number}","milestones_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/milestones{/number}","notifications_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/labels{/name}","releases_url":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/releases{/id}","created_at":"2014-05-20T18:36:23Z","updated_at":"2015-02-12T10:04:59Z","pushed_at":"2015-02-12T17:20:03Z","git_url":"git://github.com/Cal-CS-61A-Staff/ok.git","ssh_url":"git@github.com:Cal-CS-61A-Staff/ok.git","clone_url":"https://github.com/Cal-CS-61A-Staff/ok.git","svn_url":"https://github.com/Cal-CS-61A-Staff/ok","homepage":null,"size":12695,"stargazers_count":9,"watchers_count":9,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"open_issues_count":56,"forks":3,"open_issues":56,"watchers":9,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374"},"html":{"href":"https://github.com/Cal-CS-61A-Staff/ok/pull/374"},"issue":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/374"},"comments":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/issues/374/comments"},"review_comments":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374/comments"},"review_comment":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/pulls/374/commits"},"statuses":{"href":"https://api.github.com/repos/Cal-CS-61A-Staff/ok/statuses/23f53a87733822bfeb84ee028de5d532ea26404a"}}}}