Add a script to generate a kml file with all active GSoC participants
authorDaniel Hans <Daniel.M.Hans@gmail.com>
Tue, 22 Sep 2009 13:15:33 +0200
changeset 2967 676c0ca67e21
parent 2966 9ae1ee28e438
child 2968 7ba28890eb75
Add a script to generate a kml file with all active GSoC participants Only the students, mentors, and organization admins that are 'active' are exported. Students that do not have a project are not exported. Reviewed-by: Sverre Rabbelier
scripts/export_kml.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/export_kml.py	Tue Sep 22 13:15:33 2009 +0200
@@ -0,0 +1,743 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2009 the Melange authors.
+#
+# Licensed 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.
+
+"""The script which generates KML file for Google Summer of Code 2009 program.
+"""
+
+__authors__ = [
+  '"Daniel Hans" <daniel.m.hans@gmail.com>',
+]
+
+
+import sys
+import codecs
+import interactive
+
+
+from xml.dom.minidom import Document
+
+
+def _getMentoredProjects(mentor):
+  """Returns a list of projects which are mentored by a given mentor.
+  """
+
+  from soc.logic.models.student_project import logic as project_logic
+
+  filter = {
+      'mentor': mentor
+      }
+
+  return project_logic.getForFields(filter=filter)
+
+
+def _getAcceptedOrgs():
+  """Returns a list of organizations which got accepted.
+  """
+
+  from soc.logic.models.organization import logic as org_logic
+
+  filter = {
+      'status': 'active'
+      }
+
+  entities = org_logic.getForFields(filter=filter)
+
+  filter = {
+      'status': 'new'
+      }
+
+  entities += org_logic.getForFields(filter=filter)
+
+  return entities
+
+
+def _getStudentProject(entity):
+  """Returns a project for a given student.
+  """
+
+  from soc.logic.models.student_project import logic as project_logic
+
+  filter = {
+      'student': entity,
+      'status': 'accepted',
+      }
+
+  return project_logic.getForFields(filter=filter, unique=True)
+
+
+def _getAllUsers():
+  """Returns a list of all valid users.
+  """
+
+  from soc.models.user import User
+
+  gen = lambda: User.all().filter('status =', 'valid')
+  return interactive.deepFetch(gen)
+
+
+def _getAllOrgAdmins():
+  """Returns a generator of all active mentors.
+  """
+
+  from soc.models.org_admin import OrgAdmin
+
+  gen = lambda: OrgAdmin.all().filter('status = ', 'active')
+  return interactive.deepFetch(gen)
+
+
+def _getAllMentors():
+  """Returns a generator of all active mentors.
+  """
+
+  from soc.models.mentor import Mentor
+
+  gen = lambda: Mentor.all().filter('status = ', 'active')
+  return interactive.deepFetch(gen)
+
+
+def _getAllStudents():
+  """Returns a generator of all active students.
+  """
+
+  from soc.models.student import Student
+
+  gen = lambda: Student.all().filter('status = ', 'active')
+  return interactive.deepFetch(gen)
+
+
+def _getPersonStyle(doc, type):
+  """Returns <Style> element for a particular person.
+  """
+
+  if type == 'org_admin':
+    x_text, y_text = '0', '0'
+  elif type == 'mentor':
+    x_text, y_text = '128', '96'
+  elif type == 'student':
+    x_text, y_text = '64', '160'
+
+  style = doc.createElement('Style')
+
+  icon_style = doc.createElement('IconStyle')
+  style.appendChild(icon_style)
+
+  icon = doc.createElement('Icon')
+  icon_style.appendChild(icon)
+
+  href = doc.createElement('href')
+  icon.appendChild(href)
+
+  text = doc.createTextNode('root://icons/palette-5.png')
+  href.appendChild(text)
+
+  x = doc.createElement('x')
+  icon.appendChild(x)
+
+  text = doc.createTextNode(x_text)
+  x.appendChild(text)
+
+  y = doc.createElement('y')
+  icon.appendChild(y)
+
+  text = doc.createTextNode(y_text)
+  y.appendChild(text)
+
+  w = doc.createElement('w')
+  icon.appendChild(w)
+
+  text = doc.createTextNode('32')
+  w.appendChild(text)
+
+  h = doc.createElement('h')
+  icon.appendChild(h)
+
+  text = doc.createTextNode('32')
+  h.appendChild(text)
+
+  return style
+
+
+def _getLineStringStyle(doc):
+   """Returns <Style> element for a line string placemark.
+   """
+
+   style = doc.createElement('Style')
+
+   line_style = doc.createElement('LineStyle')
+   style.appendChild(line_style)
+
+   color = doc.createElement('color')
+   line_style.appendChild(color)
+
+   text = doc.createTextNode('ff00ff00')
+   color.appendChild(text)
+
+   width = doc.createElement('width')
+   line_style.appendChild(width)
+
+   text = doc.createTextNode('1')
+   width.appendChild(text)
+
+   return style
+
+
+def _getDescriptionForStudent(doc, student, project):
+  """Returns <description> element for a given student.
+  """
+
+  description = doc.createElement('description')
+
+  text = doc.createTextNode('Working on...')
+  description.appendChild(text)
+
+  description.appendChild(doc.createElement('br'))
+
+  i = doc.createElement('i')
+  description.appendChild(i)
+
+  title = doc.createTextNode(project.title)
+  i.appendChild(title)
+  description.appendChild(doc.createElement('br'))
+
+  mentor = doc.createTextNode(
+      'mentored by ' + _getName(project.mentor))
+  description.appendChild(mentor)
+  description.appendChild(doc.createElement('br'))
+
+  org = doc.createTextNode(project.scope.name)
+  description.appendChild(org)
+  description.appendChild(doc.createElement('br'))
+  description.appendChild(doc.createElement('br'))
+
+  description = _appendHomePageAndBlogContent(doc, description, student)
+
+  description = _appendStateAndCountryContnent(doc, description, student)
+
+  return description
+
+
+def _appendStateAndCountryContnent(doc, description, state, country):
+  """Appends state and country info to the description of a placemark.
+  """
+
+  if state:
+    description.appendChild(doc.createTextNode(state + ', '))
+
+  description.appendChild(doc.createTextNode(country))
+
+  return description
+
+
+def _appendHomePageAndBlogContent(doc, description, home_pages, blogs):
+  """Appends home page and blog info to the description of a placemark.
+  """
+
+  if home_pages:
+    text = doc.createTextNode('Home page:')
+    description.appendChild(text)
+    description.appendChild(doc.createElement('br'))
+
+  for home_page in home_pages:
+    description.appendChild(doc.createTextNode(home_page))
+    description.appendChild(doc.createElement('br'))
+
+  if home_pages:
+    description.appendChild(doc.createElement('br'))
+
+  if blogs:
+    text = doc.createTextNode('Blog:')
+    description.appendChild(text)
+    description.appendChild(doc.createElement('br'))
+
+  for blog in blogs:
+    description.appendChild(doc.createTextNode(blog))
+    description.appendChild(doc.createElement('br'))
+
+  if blogs:
+    description.appendChild(doc.createElement('br'))
+
+  return description
+
+
+def _getName(entity):
+  """For a given entity returns a name to be displayed.
+  """
+
+  return entity.name()
+
+
+def _getMentorDescription(doc, content):
+  """Returns <description> element for a mentor / org admin based on content.
+  """
+
+  description = doc.createElement('description')
+
+  admin = content['admin']
+  if admin:
+    text = doc.createTextNode('Organization admin for ' + admin)
+    description.appendChild(text)
+    description.appendChild(doc.createElement('br'))
+
+  projects = content['projects']
+  if projects:
+    text = doc.createTextNode('Mentoring...')
+    description.appendChild(text)
+    description.appendChild(doc.createElement('br'))
+
+  for project in projects:
+    i = doc.createElement('i')
+    description.appendChild(i)
+
+    title = doc.createTextNode(project['title'])
+    i.appendChild(title)
+    description.appendChild(doc.createElement('br'))
+
+    student = doc.createTextNode('by ' + project['student'])
+    description.appendChild(student)
+    description.appendChild(doc.createElement('br'))
+
+    organization = doc.createTextNode(project['org'])
+    description.appendChild(organization)
+    description.appendChild(doc.createElement('br'))
+
+  consults = content['consults']
+  for consult in consults:
+    text = doc.createTextNode(consult)
+    description.appendChild(text)
+    description.appendChild(doc.createElement('br'))
+
+  description.appendChild(doc.createElement('br'))
+
+  home_pages = content['home_pages']
+  blogs = content['blogs']
+  description = _appendHomePageAndBlogContent(doc, description,
+      home_pages, blogs)
+
+  state = content['state']
+  country = content['country']
+  description = _appendStateAndCountryContnent(doc, description, state,
+      country)
+
+  return description
+
+
+def _getStudentDescription(doc, content):
+  """Returns <description> element for a student based on content.
+  """
+
+  description = doc.createElement('description')
+
+  text = doc.createTextNode('Working on...')
+  description.appendChild(text)
+
+  description.appendChild(doc.createElement('br'))
+
+  project = content['project']
+  i = doc.createElement('i')
+  description.appendChild(i)
+
+  title = doc.createTextNode(project.title)
+  i.appendChild(title)
+  description.appendChild(doc.createElement('br'))
+
+  mentor = doc.createTextNode('mentored by ' + project.mentor.name())
+  description.appendChild(mentor)
+  description.appendChild(doc.createElement('br'))
+
+  org = doc.createTextNode(project.scope.name)
+  description.appendChild(org)
+  description.appendChild(doc.createElement('br'))
+  description.appendChild(doc.createElement('br'))
+
+  home_pages = content['home_pages']
+  blogs = content['blogs']
+  description = _appendHomePageAndBlogContent(doc, description,
+      home_pages, blogs)
+
+  state = content['state']
+  country = content['country']
+  description = _appendStateAndCountryContnent(doc, description, state,
+      country)
+
+  return description
+
+
+def _createFolderForMentorsAndOrgAdmins(doc):
+  """
+  """
+
+  folder = doc.createElement("Folder")
+
+  name = doc.createElement("name")
+  folder.appendChild(name)
+
+  nametext = doc.createTextNode("Mentors")
+  name.appendChild(nametext)
+
+  return folder
+
+
+def _createLineString(doc, student, mentor):
+  """Generates line string between a given student and mentor.
+  """
+
+  line_string = doc.createElement('LineString')
+
+  coordinates = doc.createElement('coordinates')
+  line_string.appendChild(coordinates)
+
+  text = doc.createTextNode(str(student[0]) + ',' + str(student[1]) + ' ' +
+      str(mentor[0]) + ',' + str(mentor[1]))
+  coordinates.appendChild(text)
+
+  altitude_mode = doc.createElement('altitudeMode')
+  line_string.appendChild(altitude_mode)
+
+  text = doc.createTextNode('clampToGround')
+  altitude_mode.appendChild(text)
+
+  extrude = doc.createElement('extrude')
+  line_string.appendChild(extrude)
+
+  text = doc.createTextNode('1')
+  extrude.appendChild(text)
+
+  tessellate = doc.createElement('tessellate')
+  line_string.appendChild(tessellate)
+
+  text = doc.createTextNode('1')
+  tessellate.appendChild(text)
+
+  return line_string
+
+
+def _createPoint(doc, longitude, latitude):
+  """Generates <Point> subtree with coordinates for a given entity.
+  """
+
+  point = doc.createElement('Point')
+
+  coordinates = doc.createElement('coordinates')
+  point.appendChild(coordinates)
+
+  text = doc.createTextNode(str(longitude) + ',' + str(latitude))
+  coordinates.appendChild(text)
+
+  return point
+
+
+def _createStudentPlacemark(doc, coordinates, content):
+  """Creates <Placemark> element for a student based on a given content.
+  """
+
+  placemark = doc.createElement('Placemark')
+
+  style = _getPersonStyle(doc, 'student')
+  placemark.appendChild(style)
+
+  name = doc.createElement('name')
+  placemark.appendChild(name)
+
+  text = doc.createTextNode(content['name'])
+  name.appendChild(text)
+
+  description = _getStudentDescription(doc, content)
+  placemark.appendChild(description)
+
+  point = _createPoint(doc, coordinates[0], coordinates[1])
+  placemark.appendChild(point)
+
+  return placemark
+
+
+def _createMentorPlacemark(doc, coordinates, content):
+  """Creates <Placemark> element for a mentor based on a given content.
+  """
+
+  placemark = doc.createElement('Placemark')
+
+  type = 'org_admin' if content['admin'] is not None else 'mentor'
+  style = _getPersonStyle(doc, type)
+  placemark.appendChild(style)
+
+  name = doc.createElement('name')
+  placemark.appendChild(name)
+
+  text = doc.createTextNode(content['name'])
+  name.appendChild(text)
+
+  description = _getMentorDescription(doc, content)
+  placemark.appendChild(description)
+
+  point = _createPoint(doc, coordinates[0], coordinates[1])
+  placemark.appendChild(point)
+
+  return placemark
+
+
+def _createLineStringPlacemark(doc, student_coordinates, mentor_coordinates):
+  """Creates <Placemark> element for a line string between given student
+     coordinates and mentor coordinates.
+  """
+
+  placemark = doc.createElement('Placemark')
+
+  line_string = _createLineString(doc, student_coordinates, mentor_coordinates)
+  placemark.appendChild(line_string)
+
+  style = _getLineStringStyle(doc)
+  placemark.appendChild(style)
+
+  return placemark
+
+
+def _processMentor(doc, org_admin, mentors, folder):
+  """Processes a student and adds information to a folder.
+  """
+
+  projects = []
+  placemarks = {}
+  longitude = None
+  latitude = None
+
+  for entity in mentors:
+    if not entity.publish_location:
+      continue
+
+    longitude, latitude = (entity.longitude, entity.latitude)
+
+    if not placemarks.get((longitude, latitude)):
+      placemarks[(longitude, latitude)] = {
+          'admin': None,
+          'projects': [],
+          'consults': [],
+          'name': entity.name(),
+          'country': entity.res_country,
+          'state': entity.res_state,
+          'home_pages': set(),
+          'blogs': set()
+          }
+
+    projects = _getMentoredProjects(entity)
+    if not projects:
+      placemarks[(longitude, latitude)]['consults'].append(
+          'Mentor for ' + entity.scope.name)
+    else:
+      for project in projects:
+        placemarks[(longitude, latitude)]['projects'].append({
+            'title': project.title,
+            'org': project.scope.name,
+            'student': project.student.name()
+            })
+
+    if entity.home_page:
+      placemarks[(longitude, latitude)]['home_pages'].add(entity.home_page)
+    if entity.blog:
+      placemarks[(longitude, latitude)]['blogs'].add(entity.blog)
+
+  if org_admin and org_admin.publish_location:
+
+    if not (longitude, latitude):
+      longitude, latitude = (org_admin.longitude, org_admin.latitude)
+
+    if not placemarks.get((longitude, latitude)):
+      placemarks[(longitude, latitude)] = {
+          'admin': None,
+          'projects': [],
+          'consults': [],
+          'name': org_admin.name(),
+          'country': org_admin.res_country,
+          'state': org_admin.res_state,
+          'home_pages': set(),
+          'blogs': set()
+          }
+
+    placemarks[(longitude, latitude)]['admin'] = org_admin.scope.name
+
+    if org_admin.home_page:
+      placemarks[(longitude, latitude)]['home_pages'].add(org_admin.home_page)
+    if org_admin.blog:
+      placemarks[(longitude, latitude)]['blogs'].add(org_admin.blog)
+
+  for coordinates, content in placemarks.iteritems():
+    placemark = _createMentorPlacemark(doc, coordinates, content)
+    folder.appendChild(placemark)
+
+
+def _processStudent(doc, student, orgs_folder):
+  """Processes a student and adds information to a folder.
+  """
+
+  if not student.publish_location:
+    return
+
+  project = _getStudentProject(student)
+
+  if not project:
+    return
+
+  folder = doc.createElement('Folder')
+
+  name = doc.createElement('name')
+  folder.appendChild(name)
+
+  name.appendChild(doc.createTextNode(student.name()))
+
+  content = {
+      'name': student.name(),
+      'project': project,
+      'country': student.res_country,
+      'state': student.res_state,
+      'home_pages': [student.home_page] if student.home_page else [],
+      'blogs': [student.blog] if student.blog else []
+      }
+
+  coordinates = student.longitude, student.latitude
+
+  placemark = _createStudentPlacemark(doc, coordinates, content)
+  folder.appendChild(placemark)
+
+  mentor = project.mentor
+
+  if mentor.publish_location:
+    mentor_coordinates = mentor.longitude, mentor.latitude
+    line_string = _createLineStringPlacemark(doc, coordinates,
+        mentor_coordinates)
+    folder.appendChild(line_string)
+
+  org = project.scope
+  org_folder = orgs_folder[org.name]
+  org_folder.appendChild(folder)
+
+
+def _processAllUsers(doc, mentors_folder, orgs_folder):
+  """Processes all users and fills folders with information based on roles.
+  """
+
+  from soc.logic.models.mentor import logic as mentor_logic
+  from soc.logic.models.org_admin import logic as org_admin_logic
+  from soc.logic.models.student import logic as student_logic
+
+  it = _getAllOrgAdmins()
+  org_admins = dict()
+  for org_admin in it:
+    org_admins[org_admin.link_id] = org_admin
+
+  it = _getAllMentors()
+  mentors = dict()
+  for mentor in it:
+    link_id = mentor.link_id
+    if link_id not in mentors:
+      mentors[link_id] = []
+    mentors[link_id].append(mentor)
+
+  it = _getAllStudents()
+  students = dict()
+  for student in it:
+    students[student.link_id] = student
+
+  link_ids = set(mentors.keys() + org_admins.keys())
+
+  for link_id in link_ids:
+    entity = org_admins.get(link_id)
+    entities = mentors.get(link_id, [])
+
+    if entity or entities:
+      _processMentor(doc, entity, entities, mentors_folder)
+      continue
+
+  link_ids = students.keys()
+  for link_id in link_ids:
+    entity = students.get(link_id)
+    if entity:
+      _processStudent(doc, entity, orgs_folder)
+
+
+def _createFolderForStudentsAndOrgs(doc):
+  """Creates <Folder> elements for all students and for all accepted
+     organizations.
+
+  Returns:
+    A tuple whose first element is a folder for students and the second
+    one is a dictionary mapping organization names with their folders.
+  """
+
+  folder = doc.createElement('Folder')
+
+  name = doc.createElement('name')
+  folder.appendChild(name)
+
+  text = doc.createTextNode('Students')
+  name.appendChild(text)
+
+  orgs = _getAcceptedOrgs()
+  org_folders = {}
+
+  for org in orgs:
+    org_folder = doc.createElement('Folder')
+    folder.appendChild(org_folder)
+
+    name = doc.createElement('name')
+    org_folder.appendChild(name)
+
+    text = doc.createTextNode(org.name)
+    name.appendChild(text)
+
+    org_folders[org.name] = org_folder
+
+  return folder, org_folders
+
+
+def generateCompleteKML():
+  """Generates complete KML file for Google Summer of Code 2009.
+  """
+
+  doc = Document()
+
+  kml = doc.createElement('kml')
+  doc.appendChild(kml)
+
+  document = doc.createElement('Document')
+  kml.appendChild(document)
+
+  mentor_folder = _createFolderForMentorsAndOrgAdmins(doc)
+  document.appendChild(mentor_folder)
+
+  student_folder, org_folders = _createFolderForStudentsAndOrgs(doc)
+  document.appendChild(student_folder)
+
+  _processAllUsers(doc, mentor_folder, org_folders)
+
+  out = codecs.open('soc_map2009.kml', 'w', 'utf-8')
+  out.write(doc.toprettyxml(indent='  '))
+  out.close()
+
+
+def main(args):
+
+  context = {
+      'export': generateCompleteKML,
+      }
+  interactive.setup()
+  interactive.remote(args, context)
+
+
+if __name__ == '__main__':
+  if len(sys.argv) < 2:
+    print "Usage: %s app_id [host]" % (sys.argv[0],)
+    sys.exit(1)
+
+  main(sys.argv[1:])