GitHub PullRequestEvent at 2014-06-01 20:54:54
Repository: ESP-Website
Actor: mgersh
Payload: {"action":"closed","number":1051,"pull_request":{"url":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/1051","id":12603207,"html_url":"https://github.com/learning-unlimited/ESP-Website/pull/1051","diff_url":"https://github.com/learning-unlimited/ESP-Website/pull/1051.diff","patch_url":"https://github.com/learning-unlimited/ESP-Website/pull/1051.patch","issue_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/1051","number":1051,"state":"closed","title":"Formstack student application module","user":{"login":"luac","id":1305639,"avatar_url":"https://avatars.githubusercontent.com/u/1305639?","gravatar_id":"eb64b8c27c34cda7a60baea6cf6d6297","url":"https://api.github.com/users/luac","html_url":"https://github.com/luac","followers_url":"https://api.github.com/users/luac/followers","following_url":"https://api.github.com/users/luac/following{/other_user}","gists_url":"https://api.github.com/users/luac/gists{/gist_id}","starred_url":"https://api.github.com/users/luac/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/luac/subscriptions","organizations_url":"https://api.github.com/users/luac/orgs","repos_url":"https://api.github.com/users/luac/repos","events_url":"https://api.github.com/users/luac/events{/privacy}","received_events_url":"https://api.github.com/users/luac/received_events","type":"User","site_admin":false},"body":"For code reviewers:\r\n\r\nI would recommend looking at the complete diff, not the individual commits, because I changed my mind about the design a bunch of times and the individual commits reflect older designs that are distracting.\r\n\r\nUsage docs here: https://github.com/learning-unlimited/ESP-Website/blob/lua-junction-app-rebase/docs/admin/student_apps.rst\r\n\r\n* **esp/esp/formstack/**: an app for working with Formstack forms in Python. It's fairly standalone. Files:\r\n * **api.py** is the official Formstack API library for Python, with minor improvements.\r\n * **objects.py** is a higher level wrapper around api.py that represents each Formstack form and submission as a Python object. Form data is fetched from the API on demand; API calls are cached. The rest of the code prefers this interface.\r\n * **signals.py** and **views.py** integrate with Formstack's \"webhook\" feature. If it's set up properly, Formstack will POST to our website whenever we get a form submission, hitting a view which sends a Django signal. This lets other parts of the code listen for form submission events. (For example, it could be used to expire caches. Actually, I haven't thought of this before, but it ought to just expire the caches in objects.py. It doesn't do that now, yet.)\r\n* **esp/esp/application/models.py**: the model layer, containing the meat of the logic of handling student applications. I think the architecture here is suboptimal, and I have some better ideas for doing things now, but I wouldn't want to delay this pull request more. I might implement them later if this module continues to be used. Models:\r\n * **FormstackAppSettings**: This is like the StudentClassRegModuleInfo but for this module. Most of the attributes here are for setting up the link between Formstack and the website; it stores which form ID the app is, which fields are which, etc.\r\n * **StudentProgramApp**: A student's application to the program. This is supposed to be generic (not Formstack-specific). Each student should only have one of these per program, although the uniqueness constraint is not enforced since students might submit the form twice and we can't do anything about that.\r\n * **StudentClassApp**: A student's application to a particular class, with a particular priority. This is supposed to be generic (not Formstack-specific). A student should have one of these per StudentProgramApp and priority.\r\n * **FormstackStudentProgramApp**: Proxy model for StudentProgramApp. There are some methods here for creating these from Formstack form data, both automagically when new apps come in (using the signal machinery mentioned above) and manually when .objects.fetch() is called (which is needed if you update something). A frontend for manual fetching does not currently exist, but probably should.\r\n * **FormstackStudentClassApp**: Proxy model for StudentClassApp. The only point of this is to have a separate admin panel entry.\r\n* **esp/esp/program/modules/handlers/formstackappmodule.py**: Student-facing module that just presents students with a Formstack form for the application, much like the medical module. (Hmm, maybe there should just be one generic \"here's a Formstack form\" module a la customforms. Oh well.) Also has a view for the financial aid form, which is also a Formstack form.\r\n* **esp/esp/program/modules/handlers/admissionsdashboard.py**: Admin and teacher facing module for reviewing apps. This is the frontend for interacting with most of the above functionality. This is supposed to be not-Formstack-specific. Most of the UI work is in the corresponding template and JS.\r\n* **Minor assorted changes**:\r\n * **esp/esp/cache/argcache.py**: adds a way to modify the cache timeout on a cached function. I don't remember why I originally wanted to modify the timeout. I think I made it longer, so that we hit Formstack less often, but I'm not sure. Regardless, it's probably good for argcache to have such an option.\r\n * **esp/esp/utils/decorators.py**: Lets you use @json_response(None) to mean \"don't do the field mapping thing that json_response usually does.\" I'm not sure this was necessary in retrospect, but I used it in a couple places.\r\n\r\nIf you're not me and you're looking at this code, you almost certainly have questions, so don't hesitate to ask!","created_at":"2014-02-17T08:56:25Z","updated_at":"2014-06-01T20:54:54Z","closed_at":"2014-06-01T20:54:54Z","merged_at":"2014-06-01T20:54:54Z","merge_commit_sha":"ffb7ad36260ca7578398b7ef599bdafc863a58bd","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/1051/commits","review_comments_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/1051/comments","review_comment_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/comments/{number}","comments_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/1051/comments","statuses_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/statuses/3f8ccb08cac9afb0bc021ad8e88c7d78d7489eb3","head":{"label":"learning-unlimited:lua-junction-app-rebase","ref":"lua-junction-app-rebase","sha":"3f8ccb08cac9afb0bc021ad8e88c7d78d7489eb3","user":{"login":"learning-unlimited","id":1150905,"avatar_url":"https://avatars.githubusercontent.com/u/1150905?","gravatar_id":"93c39b52e0adb3b3f3b998ec8ef678ce","url":"https://api.github.com/users/learning-unlimited","html_url":"https://github.com/learning-unlimited","followers_url":"https://api.github.com/users/learning-unlimited/followers","following_url":"https://api.github.com/users/learning-unlimited/following{/other_user}","gists_url":"https://api.github.com/users/learning-unlimited/gists{/gist_id}","starred_url":"https://api.github.com/users/learning-unlimited/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/learning-unlimited/subscriptions","organizations_url":"https://api.github.com/users/learning-unlimited/orgs","repos_url":"https://api.github.com/users/learning-unlimited/repos","events_url":"https://api.github.com/users/learning-unlimited/events{/privacy}","received_events_url":"https://api.github.com/users/learning-unlimited/received_events","type":"Organization","site_admin":false},"repo":{"id":2643878,"name":"ESP-Website","full_name":"learning-unlimited/ESP-Website","owner":{"login":"learning-unlimited","id":1150905,"avatar_url":"https://avatars.githubusercontent.com/u/1150905?","gravatar_id":"93c39b52e0adb3b3f3b998ec8ef678ce","url":"https://api.github.com/users/learning-unlimited","html_url":"https://github.com/learning-unlimited","followers_url":"https://api.github.com/users/learning-unlimited/followers","following_url":"https://api.github.com/users/learning-unlimited/following{/other_user}","gists_url":"https://api.github.com/users/learning-unlimited/gists{/gist_id}","starred_url":"https://api.github.com/users/learning-unlimited/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/learning-unlimited/subscriptions","organizations_url":"https://api.github.com/users/learning-unlimited/orgs","repos_url":"https://api.github.com/users/learning-unlimited/repos","events_url":"https://api.github.com/users/learning-unlimited/events{/privacy}","received_events_url":"https://api.github.com/users/learning-unlimited/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/learning-unlimited/ESP-Website","description":"A website to help manage the logistics of large short-term educational programs","fork":false,"url":"https://api.github.com/repos/learning-unlimited/ESP-Website","forks_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/forks","keys_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/keys{/key_id}","collaborators_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/teams","hooks_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/hooks","issue_events_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/events{/number}","events_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/events","assignees_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/assignees{/user}","branches_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/branches{/branch}","tags_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/tags","blobs_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/refs{/sha}","trees_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/trees{/sha}","statuses_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/statuses/{sha}","languages_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/languages","stargazers_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/stargazers","contributors_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/contributors","subscribers_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/subscribers","subscription_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/subscription","commits_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/commits{/sha}","git_commits_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/commits{/sha}","comments_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/comments{/number}","issue_comment_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/comments/{number}","contents_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/contents/{+path}","compare_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/compare/{base}...{head}","merges_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/merges","archive_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/downloads","issues_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues{/number}","pulls_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls{/number}","milestones_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/milestones{/number}","notifications_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/labels{/name}","releases_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/releases{/id}","created_at":"2011-10-25T14:30:31Z","updated_at":"2014-06-01T20:54:54Z","pushed_at":"2014-06-01T20:54:54Z","git_url":"git://github.com/learning-unlimited/ESP-Website.git","ssh_url":"git@github.com:learning-unlimited/ESP-Website.git","clone_url":"https://github.com/learning-unlimited/ESP-Website.git","svn_url":"https://github.com/learning-unlimited/ESP-Website","homepage":"","size":53470,"stargazers_count":47,"watchers_count":47,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":35,"mirror_url":null,"open_issues_count":446,"forks":35,"open_issues":446,"watchers":47,"default_branch":"main","permissions":{"admin":false,"push":false,"pull":true}}},"base":{"label":"learning-unlimited:main","ref":"main","sha":"a55a136179151672173fcc2f9180a9159c7a5c4a","user":{"login":"learning-unlimited","id":1150905,"avatar_url":"https://avatars.githubusercontent.com/u/1150905?","gravatar_id":"93c39b52e0adb3b3f3b998ec8ef678ce","url":"https://api.github.com/users/learning-unlimited","html_url":"https://github.com/learning-unlimited","followers_url":"https://api.github.com/users/learning-unlimited/followers","following_url":"https://api.github.com/users/learning-unlimited/following{/other_user}","gists_url":"https://api.github.com/users/learning-unlimited/gists{/gist_id}","starred_url":"https://api.github.com/users/learning-unlimited/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/learning-unlimited/subscriptions","organizations_url":"https://api.github.com/users/learning-unlimited/orgs","repos_url":"https://api.github.com/users/learning-unlimited/repos","events_url":"https://api.github.com/users/learning-unlimited/events{/privacy}","received_events_url":"https://api.github.com/users/learning-unlimited/received_events","type":"Organization","site_admin":false},"repo":{"id":2643878,"name":"ESP-Website","full_name":"learning-unlimited/ESP-Website","owner":{"login":"learning-unlimited","id":1150905,"avatar_url":"https://avatars.githubusercontent.com/u/1150905?","gravatar_id":"93c39b52e0adb3b3f3b998ec8ef678ce","url":"https://api.github.com/users/learning-unlimited","html_url":"https://github.com/learning-unlimited","followers_url":"https://api.github.com/users/learning-unlimited/followers","following_url":"https://api.github.com/users/learning-unlimited/following{/other_user}","gists_url":"https://api.github.com/users/learning-unlimited/gists{/gist_id}","starred_url":"https://api.github.com/users/learning-unlimited/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/learning-unlimited/subscriptions","organizations_url":"https://api.github.com/users/learning-unlimited/orgs","repos_url":"https://api.github.com/users/learning-unlimited/repos","events_url":"https://api.github.com/users/learning-unlimited/events{/privacy}","received_events_url":"https://api.github.com/users/learning-unlimited/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/learning-unlimited/ESP-Website","description":"A website to help manage the logistics of large short-term educational programs","fork":false,"url":"https://api.github.com/repos/learning-unlimited/ESP-Website","forks_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/forks","keys_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/keys{/key_id}","collaborators_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/teams","hooks_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/hooks","issue_events_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/events{/number}","events_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/events","assignees_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/assignees{/user}","branches_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/branches{/branch}","tags_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/tags","blobs_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/refs{/sha}","trees_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/trees{/sha}","statuses_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/statuses/{sha}","languages_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/languages","stargazers_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/stargazers","contributors_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/contributors","subscribers_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/subscribers","subscription_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/subscription","commits_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/commits{/sha}","git_commits_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/git/commits{/sha}","comments_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/comments{/number}","issue_comment_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/comments/{number}","contents_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/contents/{+path}","compare_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/compare/{base}...{head}","merges_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/merges","archive_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/downloads","issues_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues{/number}","pulls_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls{/number}","milestones_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/milestones{/number}","notifications_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/labels{/name}","releases_url":"https://api.github.com/repos/learning-unlimited/ESP-Website/releases{/id}","created_at":"2011-10-25T14:30:31Z","updated_at":"2014-06-01T20:54:54Z","pushed_at":"2014-06-01T20:54:54Z","git_url":"git://github.com/learning-unlimited/ESP-Website.git","ssh_url":"git@github.com:learning-unlimited/ESP-Website.git","clone_url":"https://github.com/learning-unlimited/ESP-Website.git","svn_url":"https://github.com/learning-unlimited/ESP-Website","homepage":"","size":53470,"stargazers_count":47,"watchers_count":47,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":35,"mirror_url":null,"open_issues_count":446,"forks":35,"open_issues":446,"watchers":47,"default_branch":"main","permissions":{"admin":false,"push":false,"pull":true}}},"_links":{"self":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/1051"},"html":{"href":"https://github.com/learning-unlimited/ESP-Website/pull/1051"},"issue":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/1051"},"comments":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/issues/1051/comments"},"review_comments":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/1051/comments"},"review_comment":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/pulls/1051/commits"},"statuses":{"href":"https://api.github.com/repos/learning-unlimited/ESP-Website/statuses/3f8ccb08cac9afb0bc021ad8e88c7d78d7489eb3"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"mgersh","id":2846855,"avatar_url":"https://avatars.githubusercontent.com/u/2846855?","gravatar_id":"702146e0472ad6a933f25db7dc71306e","url":"https://api.github.com/users/mgersh","html_url":"https://github.com/mgersh","followers_url":"https://api.github.com/users/mgersh/followers","following_url":"https://api.github.com/users/mgersh/following{/other_user}","gists_url":"https://api.github.com/users/mgersh/gists{/gist_id}","starred_url":"https://api.github.com/users/mgersh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mgersh/subscriptions","organizations_url":"https://api.github.com/users/mgersh/orgs","repos_url":"https://api.github.com/users/mgersh/repos","events_url":"https://api.github.com/users/mgersh/events{/privacy}","received_events_url":"https://api.github.com/users/mgersh/received_events","type":"User","site_admin":false},"comments":12,"review_comments":5,"commits":99,"additions":2993,"deletions":7,"changed_files":26}}