A Little Off Code, Computers, Photography and Guns

4May/090

GitHub Repositories Feed

I noticed at the bottom of the page on GitHub that there was an API link. I took a look at it and found it to be pretty interesting, it's actually really simple to use. You can export in xml, json and yaml. I thought to myself: "Hey it'd be great if I could put a repositories feed in the sidebar of my blog here!".

So I took a look at the JSON output since it's small and really easy to deserialize in php, so I wrote up a quick little php script on the server I'm hosting my blog at that will spit out an RSS feed of the repositories I've created on GitHub. The code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?="<?xml version=\"1.0\"?>"?>
<rss version="2.0">
  <channel>
    <title>BeMasher's GitHub Repositories</title>
    <link>http://github.com/bemasher</link>
    <description>BeMasher's GitHub Repositories</description>
    <language>en-us</language>
    <pubDate><?=date("D, d M Y G:i:s e")?></pubDate>
    <lastBuildDate><?=date("D, d M Y G:i:s e")?></lastBuildDate>
    <webMaster>bemasher@bemasher.net</webMaster>
    <ttl>5</ttl>

<?php
    $data = file_get_contents("http://github.com/api/v2/json/repos/show/bemasher");
    $data = json_decode($data, true);
   
    $today = date("D, d M Y G:i:s e");
   
    foreach($data["repositories"] as $repository) {
echo <<<ITEM
    <item>
        <title>{$repository["name"]}</title>
        <link>{$repository["url"]}</link>
        <description>{$repository["description"]}</description>
        <pubDate>$today</pubDate>
        <guid>{$repository["url"]}</guid>
    </item>

ITEM
;
    }
?>
    </channel>
</rss>

And if you look to the right you can see the RSS Widget in action displaying the output of the script. Cool huh?

Tagged as: , , , , No Comments
2Mar/090

Python ETR and Google Code Hosting

Earlier tonight I was talking to Nick a friend of mine who I've been working with recently on a ETR script. He's one of the webmasters for the University of Arizona Baja Racing Club.

I had already written my own ETR script for easy entry of time records from my google calendar to the ETR form website at my job. So I figured that i could just as easily modify it to work for him.

The main structure for his particular needs will be a main google account which the script will authenticate with. All of the users that he wants to keep time records for will simply create and share a calendar with that account. Then when the script is run it will simply authenticate with the gdata api and retrieve a list of events and their descriptions for each shared calendar on the account. All of this data is then written to a csv file of the same name of the calendar along with the work week it was done in.

The script is more or less in proof-of-concept stage and still needs a lot of polishing but in the middle of doing this I found myself wanting to have a way to organize changes and revisions. I've briefly used subversion before this and never really made a habit of using it even though I should have. I suddenly remembered that Google Code Hosting provides subversion access to open source projects. So I went ahead and made a project of the name pythonetr.

It took about 15 minutes for me to download and install TortoiseSVN, a windows shell integrated gui for SVN. I then imported the first revision of the project to the subversion repository of the project on google code. After that I sent Nick a link to the page so that if there were any feature requests, bugs anything he wanted me to know about for the project he could just submit them as issues there.

Shortly after that I made some modifications to the code since the gdata api was only returning events between specified dates only if their cooresponding UTC time was within the date range. This breaks things if you expect only events between the date ranges that are returned are within your timezone. So I made all the changes and committed the new revision.

It's really satisfying to have a personal record of all changes made to code and I really should do this more often. I'd upload all my other projects but I believe there's a lifetime limit of 10 projects total for google code hosting.

If you're interested in checking out a copy of the project, you can do so with the following command:

1
svn checkout http://pythonetr.googlecode.com/svn/trunk/ pythonetr-read-only
17Feb/090

Google Data API

I've got a friend who has been doing a lot of web development for the UA Baja Racing Club and I've been offering ideas for developing certain things he wanted on the website like electronic time sheet submission. I suggested he just make a pdf form and have that post to a php script on his site which would then add the vales submitted to a table in his mysql database for the site. The reason I suggested a pdf form is that it would automatically do form validation for him without having to write or find extra code to do that in javascript or in the php part himself.

That ended up being a little too complicated for what he was looking at and wasn't a very feasible solution since he had no real experience with sql. So I started thinking about a few other ways he could do this that would be easier for him to implement himself. Eventually I remembered I wrote a python script for this very thing a few weeks ago that I use to tally up the amount of time I worked in the last pay period for when i'm getting ready to submit my time sheets at work.

The python script uses the gdata api to access my calendars and tally up the total amount of time I worked each day and displays it in a user-friendly format for entering into the website I submit the ETR to.

My grand idea was to simply use their master google account for the club to create calendars for each person//team, share them with each person such that they have permission to modify//create events. Then modify the python script I wrote to spit out CSV files for each shared calendar for easy import into excel (where they manage all of the info for each team and their members).

If you're interested in the script I could post it, it's mostly been kludged together from the python gdata tutorials I found so it's by no means original and I've only been programming in python for a couple of weeks so forgive any glaring mistakes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
try:
    from xml.etree import ElementTree # for Python 2.5 users
except ImportError:
    from elementtree import ElementTree
import gdata.calendar.service
import gdata.service
import atom.service
import gdata.calendar
import atom
import getopt
import sys
import string
import time
import base64
import re
import datetime
import operator
from datetime import date
from datetime import time

def gCalLogin(email, password):
    calendar_service = gdata.calendar.service.CalendarService()
    calendar_service.email = email
    calendar_service.password = base64.b64decode(password)
    calendar_service.source = 'PythonETR'
    calendar_service.ProgrammaticLogin()
    return calendar_service

def FindCalendar(calendar_service, title):
    feed = calendar_service.GetOwnCalendarsFeed()
    for i, a_calendar in enumerate(feed.entry):
        if(a_calendar.title.text == title):
            return a_calendar.id.text
    return False
   
def DateRangeQuery(calendar_service, calendar_id='default', start_date='2009-01-01', end_date='2009-01-30', event_title='Work for ARL'):
    result = []
    parseISO8601 = re.compile("(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+).(\d+)([+-]\d+:\d+)")
    query = gdata.calendar.service.CalendarEventQuery(calendar_id, 'private', 'full')
    query.start_min = start_date
    query.start_max = end_date
    feed = calendar_service.CalendarQuery(query)
    for i, an_event in enumerate(feed.entry):
        if (an_event.title.text == event_title) and (an_event.event_status.value != "CANCELED"):
            for when in an_event.when:
                current_when = [parseISO8601.findall(when.start_time), parseISO8601.findall(when.end_time)]
                if(current_when not in result):
                    result.append(current_when)
    return result

def FindWeekBounds(today, weekday):
    weekstart = datetime.timedelta(days=int(weekday) + 1)
    weekend = datetime.timedelta(days=(5 - int(weekday)))
    return [today - weekstart, today + weekend]
   
calendar_service = gCalLogin("emailaddress@gmail.com", "passwordb64encoded")
work_calendar = FindCalendar(calendar_service, "maincalendarnamehere")
p = re.compile('[\w\d]*?%40group.calendar.google.com', re.IGNORECASE)
work_calendar = ''.join(p.findall(work_calendar)).replace('%40', '@')
today = datetime.date.today()
work_week = {}
start, end = FindWeekBounds(date.today(), date.today().weekday())
work_events = DateRangeQuery(calendar_service, calendar_id=work_calendar, start_date=(start - datetime.timedelta(days=7)).isoformat(), end_date=end.isoformat())
for event in work_events:
    start = [int(x) for x in event[0][0] if x[0] not in ("-", "+")]
    end = [int(x) for x in event[1][0] if x[0] not in ("-", "+")]
    start_datetime = datetime.datetime(start[0], start[1], start[2], start[3], start[4], start[5], start[6])
    end_datetime = datetime.datetime(end[0], end[1], end[2], end[3], end[4], end[5], end[6])
    duration = end_datetime - start_datetime
    try:
        work_week[start_datetime.strftime("%x")] += duration
    except KeyError:
        work_week[start_datetime.strftime("%x")] = duration
       
days = work_week.keys()
days.sort()
for day in days:
    print day, work_week[day]

I did a little more work on the script since I posted the code on pastebin and I found a much simpler method for retrieving lists of calendars:

1
2
3
4
5
6
7
8
9
10
11
12
def GetAllCalendars(calendar_service):
    feed = calendar_service.GetAllCalendarsFeed()
    return map(lambda x: x[1], list(enumerate(feed.entry)))

def GetUserCalendars(calendar_service):
    feed = calendar_service.GetOwnCalendarsFeed()
    return map(lambda x: x[1], list(enumerate(feed.entry)))
   
def GetSharedCalendars(calendar_service):
    return filter(lambda x: x.title.text not in map(lambda y: y.title.text,
        GetUserCalendars(calendar_service)),
        GetAllCalendars(calendar_service))