Blog about ongoing development of Melange project. Melange is a web application for representing Open Source contribution workflows, such as the existing Google Summer of Code TM (GSoC) program or Google Highly Open Participation Contest TM (GHOP).
This week I need to post remaining patches, especially the generic iconic dashboard. I just posted early so I can have much time iterating the review process and hopefully got the patches submitted this week. The generic dashboard class is now placed in app/soc/views/dashboard.py. It contains the underlying view base for iconic dashboard. Every nested-iconic-dashboard should be inherited from Dashboard class. You can take a loot at admin.py, dashboard.py and org_admin_dashboard.py views to get the idea how to use Dashboard class. Now all related base dashboard templates were placed in v2/soc/dashboard directory. It contains the base.html and _user_action.html. All stylesheet rules should be defined inside v2/gsoc/dashboard.css.
There were changes on the melange.list and melange.dependency JS after refactoring the dashboard. The changes were to hold the lists to be queued and executed when the lists were rendered inside the dashboard. After applying the changes, I run the test and it broke in the test_admin.py. I figure out the case immediately, should be the assertTemplate. Yeah, there were some templates removed and added. After fixing the test, I post all the patches and ping Daniel. I hope I can run fast for the review process ;)
Only a week is left for GSoC to end and I need to finish testing all the important views as soon as possible. I had been working on views.org_profile, profile_show, accepted_orgs, proposal_review, duplicates and proposal_review this week. Testing views is turning out to be a little more involved and complicated task as compared to testing the logic. I got stuck at some places and so could not submit them for review. I had thought that I would be able to finish the views much earlier and start functional testing but I was not fast enough and also I could not devote 10+ hours per day during the weekends as I had promised in the proposal due to heavy course work, classes and personal issues.
I will be trying to commit as much tests as possible in this week and work on the remaining tests after GSoC. I aim to work on functional testing and buildbot after GSoC. Lets hope for the best :).
The GSoC 2011 program will end shortly. Last week I was working on the account management, assign host, adding evaluation group and dashboard. There's a problem with Django test client that I couldn't figure out. The handler always treat self.data.POST as regular dict for every requests (in my case via POST) made from Django test client. Since in validate method there's a line that expect QueryDict instance, by calling getlist method self.data.POST.getlist('assign_program'), the test always fail. Maybe I missed something here, so I read the client.py code from Django that comes along with Google App Engine SDK. It took me two days or more to trace this problem. I don't think we should remove getlist from the handler nor hacking the django test client. So, I left the test ATM and move to another to do list, that's it, the dashboard.
The dashboard will be moved to soc/views/helpers/dashboard.py and the code itself is self explanatory:
class Dashboard(Template):
"""Base dashboard for admin page
"""
def __init__(self, request, data, subpages=None):
"""Initializes the dashboard.
Args:
request: The HTTPRequest object
data: The RequestData object
subpages: Subpages of current dashboard
"""
self.request = request
self.data = data
self.subpages = subpages
def getSubpagesLink(self):
"""Returns the link to other dashboard that appears
on top of the dashboard.
"""
return self.subpages
def templatePath(self):
"""Returns the path to the template that should be used in render()
"""
return 'v2/modules/gsoc/dashboard/dashboard.html'
def _divideSubPages(self, subpages):
"""Returns the subpages divided into two columns.
"""
middle_ceil = int(math.ceil(float(len(subpages))/2))
The templates is improved to be able to handle list components that we have seen from regular dashboard. I hope the patch will be posted for reviewing process lately this week and pushed before the program ends.
I worked I tested gsoc.views.duplicates module. I have not submitted my tests which I wrote for org_profile, profile_show and student_forms for review as there is a need of some access checks to be defined new for the respective module in the codebase. I was rechecking my tests for org_profile and I felt that the timeline should also be checked if a program is active or not. I put this in the mailing list and Lennard suggested that isProgramActive be renamed to isProgramVisible and a new method isProgramRunning be introduced. Those pages which remain active after gsoc can include isProgramVisible in their access checks and which are current program specific can include isProgramRunning. I submitted the patch for the access checks and Lennard and Sverre reviewed them. I will be accommodating the changes soon.
There was also a problem with our coverage module which is outdated and so it does not work with the latest Nose 1.1.2. I reported the issue with Nose and they suggested that we use coverage > 3.0. Leo tried including it in the buildout dependencies so that the coverage module is always the latest but it too did not work. Just replacing the old coverage module with the latest coverage modules works fine.
My final decision about cross-domain requests: They can be headache. Especially if your requests are bound on some headers. There are new recommendations for this like "Cross Origin Resource Sharing". But this is so new to apply because it makes your application browser dependent. There are still many users on internet using ancient browsers and we can't force them to use latest version of specific browsers. Also server we're trying to access must support this. Because we actually asking server if it accepts some parameters, headers etc. Besides this, jsonp and script methods may be enough for lots of purposes. But to make oauth authenticated requests to gdata server, it wasn't. So i changed my approach. I saw oauth gadgets use the same approach: providing a proxy url on same domain that serves as a gateway and removes all cross-domain concerns.
That proxy url doesn't care about what request does. It just takes method, gdata server, url, data, headers as parameters and makes a request to gdata server and returns response directly to the client.
After resolving cross-domain request problem, i started to develop "list exporting" feature. For now i'm able to create an empty spreadsheet when user clicks "export to spreadsheet" button. Here are some screenshots of current state:
Button for exporting:
Uploading may take time, so it's stressed in a dialog window.
After upload complete, user may click to see the document:
GSoC is near to the final evaluation and I in a run to catch all my TODO. Last week, I wrote some handlers for PA to manage account and assign a user to be a host. PA can assign programs to be hosted by particular user in edit user page. Here's how it looks:
The code is somewhat similar to assign_mentors.py and project_details.py. To set a user as a host, PA needs:
Given an account to be set as a host, go to the Lookup page in the admin dashboard.
If the account is found then click the "Edit user" link
In the edit user form, there's a box at the bottom (see picture above) that contains program selection. To set multiple programs to be hosted by the user, click "Add new" link. If done with the selection, click the "SET AS A HOST" button
Actually there's some features that I've in mind such as add / edit sponsor, programs list that contains list of program name and its hosts as cols, page to view readonly program that in inactive state, and of course the page to create new program. I'll hold thus things for a moment because the dashboard is still being refactored and I promised to finish it by Aug 6th. I am late two days here.
Browsers have some restrictions for cross-domain Javascript requests due to some security issues. For "List exporting" from client side, we need to make cross-domain requests to Google from user. Before this jsonp was only standart that i know as a solution. Jsonp allows loading a json from a remote web server. But i knew GData protocol supports XML format data exchange. I tried to find a solution to load a cross-domain XML source. No solution was neat enough to apply.
Script Approach
Then i thought GData should support JSON of course, and found related document :) We should just have to add a "alt=json" parameter to url GET params. Same page also was providing a method to access resources from a cross-domain with JavaScript. We should call a special script that calls our callback with related json as parameter when page is loaded. Here is an example script:
which returns a javascript response with a form in which json response is embed.
listEvents({"version":"1.0" ..... })
This provides another way for making cross-domain requests. In this solution server must support this method with a special effort to form a javascript response instead of just interpretting request as a regular json request.
Http Access Control
This approach was good but unfortunately not enough for our purpose because we need to set Authentication header with request. So i returned back to jsonp. I thought it should be possible to make a jsonp request and add a "Authentication" header with request like that:
This was almost working until i encountered with another cross-domain restriction. Sending headers with a cross-domain request was limited to another standard. I read this document about "Cross-Origin Resource Sharing". As far as i understand from document, For sending headers with request, this is defining a way for browser to first ask to server if it allows given headers, then makes actual request. This sounds good but because it's a new recommendation and some browsers may not support it (and perhaps GData server too) , i skipped this. Firefox supports this after 3.5 version.
At the end
I learned some stuff but still was not happy as there wasn't a way sending OAuth header with request. GData documentation contains AuthSub authentication over Javascript but i couldn't find anything related OAuth with JavaScript in which we will provide OAuth header. Then, while i was hopelessly playing with OAuth playground, saw that choice in form:
Put oauth params in:
This was just i was looking for. We were able to pass oauth params with url instead of header. This was something not documented in GData OAuth documentation. I was lucky to find this out.
At the and my approach was shaped: Make a jsonp request, put oauth params inside url.
Note: This didn't work either, to see my final solution to make Javascript requests see next post by me.