import datetime from datetime import date import urllib2 import json import time import re import io ########################### # # Produces three files containing possible Apache-related meetups. One # is formatted to paste onto a mailing list. One is suggested tweets. # One is for pasting into apache.org/events/meetups.mdtext # # Note that these are POSSIBLY Apache-related. # It would be nice to only select group categories that are Apache-related, # but it does not appear to be possible to enumerate them. There may be new ones. # So the code skips groups in categories which have referenced Apache in the past # but which are clearly not relevant. # # These lists should be manually filtered before they are used anywhere publicly. # If additional references slip through, please update the skip_groups field. # # See also note below about the API key. # # rbowen@apache.org # 29 May 2015 # ########################### # Magic import sys # sys.setdefaultencoding is cancelled by site.py reload(sys) # to re-enable sys.setdefaultencoding() def importMeetups(): print "Rounding up the ponies ..." # Note that this API key is *my* API key (rbowen) and if we start using # it more than a few dozen times an hour it's likely to get revoked. # Please play nice. key = "3a7711454d145e404e531c2ee6f391d" # Only want data for next fortnight (default is 1 month) url = "https://api.meetup.com/2/open_events?time=,2w&text=apache&sign=true&key=" + key print "Fetching meetups ..." response = urllib2.urlopen(url) m = response.read() print "Parsing results ..." r = json.loads(m) meetups = r['results'] groups = {} print "Fetching group details ..." for meetup in meetups: groups[ str( meetup['group']['id'] ) ] = meetup['group']['name'] keys = groups.keys() keyarg = ",".join( keys ) group_url = "https://api.meetup.com/2/groups?&sign=true&photo-host=public&group_id=" + keyarg + "&key=" + key response = urllib2.urlopen( group_url ) m = response.read() r = json.loads(m) grps = r['results'] print "Writing raw JSON data to 'meetups.json' and 'groups.json'" with io.open('meetups.json', 'w', encoding='utf-8') as raw: raw.write(json.dumps(meetups, indent=4, ensure_ascii=False)) raw.close() with io.open('groups.json', 'w', encoding='utf-8') as raw: raw.write(json.dumps(grps, indent=4, ensure_ascii=False)) raw.close(); def createFiles(): print "Loading meetups database..." # A week for twitter and mailing list ... week = 7 # Two weeks for the website twoweek = 14 now = datetime.datetime.now() nowts = time.mktime(now.timetuple()) with open('meetups.json') as data_file: tmp = json.load(data_file) # sort here - the 'order=time' API qualifier does not seem to work properly # using an exact sort (i.e. with id) helps reduce arbitrary ordering changes in the output file meetups = sorted(tmp, key=lambda k: str(k['time'] +k['utc_offset']) + k['id']) with open('groups.json') as data_file: grps = json.load(data_file) grp_deets = {} for g in grps: grp_deets[ g['id'] ] = g seen = set() print "Ok, ready to print meetup details ..." weeklater = (nowts * 1000 ) + ( week * 86400 * 1000 ) twoweeklater = (nowts * 1000 ) + ( twoweek * 86400 * 1000 ) tweets = io. open('meetups.tweets', 'w', encoding='utf-8') mlist = io.open('meetups.mlist', 'w', encoding='utf-8') website = io.open('meetups.mdtext', 'w', encoding='utf-8') # Standard header for website page: website.write( unicode('''Title: Upcoming Apache-related Meetups Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---------- # Upcoming Apache-related Meetups The following are Meetups that we're aware of in the coming two weeks. We also [list the major Apache-related conferences](http://community.apache.org/calendars/) coming up separately. Please feel free to notify us (dev@community.apache.org) if you're aware of events that are missing, Thanks. Also, the instructions for updating this page are in the [README](/events/README.txt) file in this directory. N.B. Dates are in local-time ''')) # Standard intro to mailing list post mlist.write( unicode('''The following are the meetups I'm aware of in the coming week where Apache enthusiasts are likely to be present. If you know of others, please let me know, and/or add them to http://apache.org/events N.B. Dates are in local-time If there's a meetup in your area, please consider attending. If you attend, please consider taking a few photos, and possibly even writing up a brief summary of what was covered. --Rich ''')) # These group['shortname'] values are unlikely to be relevant: skip_groups = dict.fromkeys(['arts-culture', 'health-wellbeing', 'hobbies-crafts', 'language', 'music', 'new-age-spirituality', 'fitness', 'socializing', 'cars-motorcycles', 'parents-family', 'community-environment', 'outdoors-adventure', 'photography', 'singles']) # Note: these ones do have relevant meetings (though the name suggests otherwise): # career-business used_groups = {} # collect the unskipped groups for meetup in meetups: eventts = int( meetup['time'] + meetup['utc_offset'] ) eventtime = date.fromtimestamp( eventts/1000 ) t = eventtime.strftime("%A %B %d") # Skip it if we've already seen it uniq = meetup['name'] + t if uniq in seen: continue seen.add( uniq ) # Group information ... grp = grp_deets[ meetup['group']['id'] ] # is the group category unlikely to be related to the ASF? shortname = grp['category']['shortname'] if shortname in skip_groups: print "=== Skipping " + shortname.encode('utf_8') + ' -- ' + meetup['name'].encode('utf_8') continue used_groups[shortname] = grp # Pick up the location details from the venue, as it may be different from group loc state = None country = '' if 'venue' in meetup: city = meetup['venue']['city'] country = meetup['venue']['country'].upper() if 'state' in meetup['venue']: state = meetup['venue']['state'].upper() else: # state may be missing from venue, try to fix this # state is not always correct outside US # if the group is based at the same city, use its state: if country == 'US' and grp['city'] == city and 'state' in grp.keys(): state = grp['state'] else: city = 'No venue specified; group is based in ' + grp['city'] if 'state' in grp.keys(): state = grp['state'] country = grp['country'] # For the website ... eventout = "* " + t + ' [' + meetup['name'] + '](' + meetup['event_url'] + "), " + city if state: eventout = eventout + ', ' + state if country != '': eventout = eventout + ', ' eventout = eventout + country + "\n" website.write( unicode(eventout) ) # For everything else, a week is enough if eventts > weeklater: continue # For Twitter eventout = t + ' in ' + city if state: eventout = eventout + ', ' + state if country != '': eventout = eventout + ', ' eventout = eventout + country + ': ' + meetup['name'] + ' - ' + meetup['event_url'] + " #Apache #Meetup\n" tweets.write( unicode( eventout )) # For mailing list eventout = '* ' + t + ' in ' + city if state: eventout = eventout + ', ' + state if country != '': eventout = eventout + ', ' eventout = eventout + country + ': ' + meetup['name'] + ' - ' + meetup['event_url'] + "\n\n" mlist.write( unicode( eventout )) # Barn door tweets.close() mlist.close() website.close() # show the groups in case some need to be added to skip_groups print "Groups used (id,category):" for g in used_groups: print "%-10s %s" % (used_groups[g]['id'],used_groups[g]['category']) print "Done! Check out meetups.mlist, meetups.tweet and meetups.mdtext\n"