scripts/stats.py
author Mario Ferraro <fadinlight@gmail.com>
Sun, 15 Nov 2009 22:12:20 +0100
changeset 3093 d1be59b6b627
parent 3016 63625e7e0cac
permissions -rwxr-xr-x
GMaps related JS changed to use new google namespace. Google is going to change permanently in the future the way to load its services, so better stay safe. Also this commit shows uses of the new melange.js module. Fixes Issue 634.

#!/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.

"""Starts an interactive shell with statistic helpers.
"""

__authors__ = [
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
]


import cPickle
import datetime
import operator
import sys
import time

import interactive


def dateFetch(queryGen, last=None, batchSize=100):
  """Iterator that yields an entity in batches.

  Args:
    queryGen: should return a Query object
    last: used to .filter() for last_modified_on
    batchSize: how many entities to retrieve in one datastore call

  Retrieved from http://tinyurl.com/d887ll (AppEngine cookbook).
  """

  from google.appengine.ext import db

   # AppEngine will not fetch more than 1000 results
  batchSize = min(batchSize,1000)

  query = None
  done = False
  count = 0

  while not done:
    print count
    query = queryGen()
    query.order('last_modified_on')
    if last:
      query.filter("last_modified_on > ", last)
    results = query.fetch(batchSize)
    for result in results:
      count += 1
      yield result
    if batchSize > len(results):
      done = True
    else:
      last = results[-1].last_modified_on


def addKey(target, fieldname):
  """Adds the key of the specified field.
  """

  result = target.copy()
  result['%s_key' % fieldname] = target[fieldname].key().name()
  return result


def getEntities(model):
  """Returns all entities as dictionary keyed on their id_or_name property.
  """

  def wrapped():
    gen = lambda: model.all()
    it = interactive.deepFetch(gen)

    entities = [(i.key().id_or_name(), i) for i in it]
    return dict(entities)

  return wrapped


def getProps(last=None):
  """Returns all proposals as a list of dictionaries.
  """

  key_order = [
      'link_id', 'scope_path', 'title', 'abstract', 'content',
      'additional_info', '_mentor', 'possible_mentors', 'score',
      'status', '_org', 'created_on', 'last_modified_on']

  from soc.models.student_proposal import StudentProposal

  gen = lambda: StudentProposal.all()

  it = dateFetch(gen, last)

  proposals = [(i.key().name(), i.toDict(key_order)) for i in it]
  if proposals:
    last = i.last_modified_on # last modified entity
  else:
    last = datetime.datetime.now()

  return dict(proposals), last


def orgStats(target, orgs):
  """Retrieves org stats.
  """

  from soc.logic import dicts

  orgs = [(v.key(), v) for k, v in orgs.iteritems()]
  orgs = dict(orgs)

  grouped = dicts.groupby(target.values(), '_org')

  grouped = [(orgs[k], v) for k, v in grouped.iteritems()]
  popularity = [(k.link_id, len(v)) for k, v in grouped]

  return dict(grouped), dict(popularity)


def countStudentsWithProposals():
  """Retrieves number of Students who have submitted at least one Student Proposal.
  """

  proposals = getStudentProposals()
  students = {}

  for proposal_key in proposals.keys():
    students[proposals[proposal_key].scope_path] = True

  return len(students)


def printPopularity(popularity):
  """Prints the popularity for the specified proposals.
  """

  g = operator.itemgetter(1)

  for item in sorted(popularity.iteritems(), key=g, reverse=True):
    print "%s: %d" % item


def saveValues(values, saver):
  """Saves the specified popularities.
  """

  import logging
  from google.appengine.ext import db

  from soc.models.organization import Organization

  def txn(key, value):
    org = Organization.get_by_key_name(key)
    saver(org, value)
    org.put()

  for key, value in sorted(values.iteritems()):
    print key
    db.run_in_transaction_custom_retries(10, txn, key, value)

  print "done"


def addFollower(follower, proposals, add_public=True, add_private=True):
  """Adds a user as follower to the specified proposals.

  Args:
    follower: the User to add as follower
    proposals: a list with the StudnetProposals that should be subscribed to
    add_public: whether the user is subscribed to public updates
    add_private: whether the user should be subscribed to private updates
  """

  from soc.models.review_follower import ReviewFollower

  result = []

  for i in proposals:
     properties = {
       'user': follower,
       'link_id': follower.link_id,
       'scope': i,
       'scope_path': i.key().name(),
       'key_name': '%s/%s' % (i.key().name(), follower.link_id),
       'subscribed_public': add_public,
       'subscribed_private': add_private,
     }

     entity = ReviewFollower(**properties)
     result.append(entity)

  return result


def convertProposals(org):
  """Convert all proposals for the specified organization.

  Args:
    org: the organization for which all proposals will be converted
  """

  from soc.logic.models.student_proposal import logic as proposal_logic
  from soc.logic.models.student_project import logic as project_logic

  proposals = proposal_logic.getProposalsToBeAcceptedForOrg(org)

  print "accepting %d proposals, with %d slots" % (len(proposals), org.slots)

  for proposal in proposals:
    fields = {
        'link_id': 't%i' % (int(time.time()*100)),
        'scope_path': proposal.org.key().id_or_name(),
        'scope': proposal.org,
        'program': proposal.program,
        'student': proposal.scope,
        'title': proposal.title,
        'abstract': proposal.abstract,
        'mentor': proposal.mentor,
        }

    project = project_logic.updateOrCreateFromFields(fields, silent=True)

    fields = {
        'status':'accepted',
        }

    proposal_logic.updateEntityProperties(proposal, fields, silent=True)

  fields = {
      'status': ['new', 'pending'],
      'org': org,
      }

  querygen = lambda: proposal_logic.getQueryForFields(fields)
  proposals = [i for i in interactive.deepFetch(querygen, batchSize=10)]

  print "rejecting %d proposals" % len(proposals)

  fields = {
      'status': 'rejected',
      }

  for proposal in proposals:
    proposal_logic.updateEntityProperties(proposal, fields, silent=True)


def startSpam():
  """Creates the job that is responsible for sending mails.
  """

  from soc.logic.models.job import logic as job_logic
  from soc.logic.models.priority_group import logic as priority_logic
  from soc.logic.models.program import logic as program_logic

  program_entity = program_logic.getFromKeyName('google/gsoc2009')

  priority_group = priority_logic.getGroup(priority_logic.EMAIL)
  job_fields = {
      'priority_group': priority_group,
      'task_name': 'setupStudentProposalMailing',
      'key_data': [program_entity.key()]}

  job_logic.updateOrCreateFromFields(job_fields)


def startUniqueUserIdConversion():
  """Creates the job that is responsible for adding unique user ids.
  """

  from soc.logic.models.job import logic as job_logic
  from soc.logic.models.priority_group import logic as priority_logic

  priority_group = priority_logic.getGroup(priority_logic.CONVERT)
  job_fields = {
      'priority_group': priority_group,
      'task_name': 'setupUniqueUserIdAdder'}

  job_logic.updateOrCreateFromFields(job_fields)


def reviveJobs(amount):
  """Sets jobs that are stuck in 'aborted' to waiting.

  Args:
    amount: the amount of jobs to revive
  """

  from soc.models.job import Job

  query = Job.all().filter('status', 'aborted')
  jobs = query.fetch(amount)

  if not jobs:
    print "no dead jobs"

  for job in jobs:
     job.status = 'waiting'
     job.put()
     print "restarted %d" % job.key().id()


def deidleJobs(amount):
  """Sets jobs that are stuck in 'started' to waiting.

  Args:
    amount: the amount of jobs to deidle
  """

  from soc.models.job import Job

  query = Job.all().filter('status', 'started')
  jobs = query.fetch(amount)

  if not jobs:
    print "no idle jobs"

  for job in jobs:
     job.status = 'waiting'
     job.put()
     print "restarted %d" % job.key().id()


def deleteEntities(model, step_size=25):
  """Deletes all entities of the specified type
  """

  print "Deleting..."
  count = 0

  while True:
    entities = model.all().fetch(step_size)

    if not entities:
      break

    for entity in entities:
      entity.delete()

    count += step_size

    print "deleted %d entities" % count

  print "Done"


def loadPickle(name):
  """Loads a pickle.
  """

  f = open(name + '.dat')
  return cPickle.load(f)


def dumpPickle(target, name):
  """Dumps a pickle.
  """

  f = open("%s.dat" % name, 'w')
  cPickle.dump(target, f)


def addOrganizationToSurveyRecords(survey_record_model):
  """Set Organization in SurveyRecords entities of a given model.
  """
  
  print "Fetching %s." % survey_record_model.__name__
  getSurveyRecord = getEntities(survey_record_model)
  survey_records = getSurveyRecord()
  survey_records_amount = len(survey_records)
  print "Fetched %d %s." % (survey_records_amount, survey_record_model.__name__)
  
  counter = 0
  
  for key in survey_records.keys():
    survey_records[key].org = survey_records[key].project.scope
    survey_records[key].put()
    
    counter += 1
    print str(counter) + '/' + str(survey_records_amount) + ' ' + str(key)
    
  print "Organization added to all %s." % survey_record_model.__name__


def setOrganizationInSurveyRecords():
  """Sets Organization property in ProjectSurveyRecords 
  and GradingProjectSurveyRecords entities.
  """
  from soc.models.project_survey_record import ProjectSurveyRecord
  from soc.models.grading_project_survey_record \
      import GradingProjectSurveyRecord
  
  addOrganizationToSurveyRecords(ProjectSurveyRecord)
  addOrganizationToSurveyRecords(GradingProjectSurveyRecord)


def exportStudentsWithProjects(csv_filename, scope_path_start=''):
  """Exports all Students who have a project assigned.

  Args:
    csv_filename: the name of the file where to save the CSV export
    scope_path_start: The string with which the scope_path of the project
      should start with. Can be used to select which sponsor, program or org
      the projects should belong to.
  """
  # TODO(Pawel.Solyga): Add additional Program parameter to this method 
  # so we export students from different programs
  # TODO(Pawel.Solyga): Make it universal so it works with both GHOP 
  # and GSoC programs

  from soc.models.student_project import StudentProject
  from soc.models.student import Student
  from soc.models.organization import Organization

  # get all projects
  getStudentProjects = getEntities(StudentProject)
  student_projects = getStudentProjects()

  student_projects_amount = len(student_projects)
  print "Fetched %d Student Projects." % student_projects_amount

  print "Fetching Student entities from Student Projects."
  accepted_students = {}
  student_extra_data = {}
  counter = 0

  for student_project in student_projects.values():
    counter += 1

    if student_project.status == 'invalid' or not \
        student_project.scope_path.startswith(scope_path_start):
      # no need to export this project
      continue

    student_entity = student_project.student

    student_key = student_entity.key().id_or_name()
    accepted_students[student_key] = student_entity

    org_name = student_project.scope.name

    extra_data = {}
    extra_data['organization'] = org_name
    extra_data['project_status'] = student_project.status
    student_extra_data[student_key] = extra_data

    print '%s/%s %s (%s)' %(counter, student_projects_amount,
                            student_key, org_name)

  print "All Student entities fetched."

  students_key_order = ['link_id', 'given_name', 'surname', 
      'document_name', 'email', 'res_street', 'res_city', 'res_state',
      'res_country', 'res_postalcode', 'phone', 'shipping_street',
      'shipping_city', 'shipping_state', 'shipping_country',
      'shipping_postalcode', 'birth_date', 'tshirt_size', 'tshirt_style',
      'school_name', 'school_country', 'major', 'degree']

  print "Preparing Students data for export."
  students_data = []

  for student_key, student_entity in accepted_students.iteritems():
    # transform the Student into a set of dict entries
    prepared_data = student_entity.toDict(students_key_order)

    # add the additional fields
    extra_data = student_extra_data[student_key]
    prepared_data['organization'] = extra_data['organization']
    prepared_data['project_status'] = extra_data['project_status']

    # append the prepared data to the collected data
    students_data.append(prepared_data)

  # append the extra fields to the key_order
  students_key_order.append('organization')
  students_key_order.append('project_status')

  saveDataToCSV(csv_filename, students_data, students_key_order)
  print "Students with Projects exported to %s file." % csv_filename


def exportUniqueOrgAdminsAndMentors(csv_filename, scope_path_start=''):
  """Exports Org Admins and Mentors to a CSV file, one per User.

  Args:
    csv_filename: the name of the csv file to save
    scope_path_start: the start of the scope path of the roles to get could be
      google/gsoc2009 if you want to export all GSoC 2009 Org Admins and
      Mentors.
  """

  from soc.models.mentor import Mentor
  from soc.models.org_admin import OrgAdmin

  print 'Retrieving all Mentors'
  mentors = getEntities(Mentor)()
  all_mentors = mentors.values()

  print 'Retrieving all Org Admins'
  org_admins = getEntities(OrgAdmin)()
  all_org_admins = org_admins.values()

  print 'Combining the list of Mentors and Org Admins'
  unique_users = {}
  all_users = []
  all_users.extend(all_mentors)
  all_users.extend(all_org_admins)

  for user in all_users:
    if not user.scope_path.startswith(scope_path_start) or \
        user.status == 'invalid':
      # not the correct program or valid user
      continue

    unique_users[user.link_id] = user

  export_fields = ['link_id', 'given_name', 'surname', 
      'document_name', 'email', 'res_street', 'res_city', 'res_state',
      'res_country', 'res_postalcode', 'phone', 'shipping_street',
      'shipping_city', 'shipping_state', 'shipping_country',
      'shipping_postalcode', 'birth_date', 'tshirt_size', 'tshirt_style']

  print 'Preparing the data for export'
  data = [user.toDict(field_names=export_fields) for user in \
          unique_users.values()]

  print 'Exporting the data to CSV'
  saveDataToCSV(csv_filename, data, export_fields)
  print "Exported Org admins and Mentors (1 per User) to %s file." % csv_filename


def saveDataToCSV(csv_filename, data, key_order):
  """Saves data in order into CSV file.

  This is a helper function used for exporting CSV data.
  
  Args:
    csv_filename: The name of the file where to save the CSV data
    data: the data dict to write to CSV
    key_order: the order in which to export the data in data dict
  """

  import csv
  import StringIO

  from soc.logic import dicts

  file_handler = StringIO.StringIO()

  # ignore the extra data
  writer = csv.DictWriter(file_handler, key_order, extrasaction='ignore', dialect='excel')
  writer.writerow(dicts.identity(key_order))

  # encode the data to UTF-8 to ensure compatibiliy
  for row_dict in data:
    for key in row_dict.keys():
      value = row_dict[key]
      if isinstance(value, basestring):
        row_dict[key] = value.encode("utf-8")
      else:
        row_dict[key] = str(value)
    writer.writerow(row_dict)

  csv_data = file_handler.getvalue()
  csv_file = open(csv_filename, 'w')
  csv_file.write(csv_data)
  csv_file.close()


def exportOrgsForGoogleCode(csv_filename, gc_project_prefix='', 
                            scope_path_start=''):
  """Export all Organizations from given program as CSV.
      
  CSV file will contain 3 columns: organization name, organization google 
  code project name, organization description.
  
  Args:
    csv_filename: the name of the csv file to save
    gc_project_prefix: Google Code project prefix for example
      could be google-summer-of-code-2009- for GSoC 2009
    scope_path_start: the start of the scope path of the roles to get could be
      google/gsoc2009 if you want to export all GSoC 2009 Organizations.
  """
  from soc.models.organization import Organization
  
  print 'Retrieving all Organizations'
  orgs = getEntities(Organization)()
  orgs_export = []
  
  print 'Preparing data for CSV export'
  for key in orgs.keys():
    if not orgs[key].scope_path.startswith(scope_path_start):
      continue
    
    org_for_export = {} 
    org_short_name = orgs[key].short_name
    org_short_name = org_short_name.replace(' ','-').replace('.', '')
    org_short_name = org_short_name.replace('/','-').replace('!','').lower()
    org_for_export['org_description'] = orgs[key].description
    org_for_export['org_name'] = orgs[key].name
    org_for_export['google_code_project_name'] = gc_project_prefix + \
        org_short_name
    orgs_export.append(org_for_export)

  export_fields = ['org_name', 'google_code_project_name', 'org_description']
  print 'Exporting the data to CSV'
  saveDataToCSV(csv_filename, orgs_export, export_fields)
  print "Exported Organizations for Google Code to %s file." % csv_filename


def exportRolesForGoogleCode(csv_filename, gc_project_prefix='', 
                             scope_path_start=''):
  """Export all Students/Mentors/OrgAdmins Roles from given program as CSV.
      
  CSV file will contain 3 columns: google_account, organization google 
  code project name and role (project member or project owner).
  
  Args:
    csv_filename: the name of the csv file to save
    gc_project_prefix: Google Code project prefix for example
      could be google-summer-of-code-2009- for GSoC 2009
    scope_path_start: the start of the scope path of the roles to get could be
      google/gsoc2009 if you want to export all GSoC 2009 Organizations.
  """
  from soc.models.org_admin import OrgAdmin
  from soc.models.student_project import StudentProject
  
  # get all projects
  getStudentProjects = getEntities(StudentProject)
  student_projects = getStudentProjects()
  org_admins = getEntities(OrgAdmin)()
  all_org_admins = org_admins.values()
  
  org_admins_by_orgs = {}
  students_by_orgs = {}
  mentors_by_orgs = {}
  
  for org_admin in all_org_admins:
      
    if not org_admin.scope_path.startswith(scope_path_start):
      continue
      
    org_short_name = org_admin.scope.short_name
    org_short_name = org_short_name.replace(' ','-').replace('.', '')
    org_short_name = org_short_name.replace('/','-').replace('!','').lower()
    if gc_project_prefix + org_short_name not in org_admins_by_orgs.keys():
      org_admins_by_orgs[gc_project_prefix + org_short_name] = []
    
    org_admins_by_orgs[gc_project_prefix + \
        org_short_name].append(str(org_admin.user.account))
    print 'OrgAdmin ' + str(org_admin.user.account) + \
        ' for ' + gc_project_prefix + org_short_name
  
  for student_project in student_projects.values():

    if student_project.status != 'accepted' or not \
      student_project.scope_path.startswith(scope_path_start):
      # no need to export this project
      continue
    
    student_entity = student_project.student
    mentor_entity = student_project.mentor
    org_short_name = student_project.scope.short_name
    org_short_name = org_short_name.replace(' ','-').replace('.', '')
    org_short_name = org_short_name.replace('/','-').replace('!','').lower()
    if gc_project_prefix + org_short_name not in students_by_orgs.keys():
      students_by_orgs[gc_project_prefix + org_short_name] = []
    students_by_orgs[gc_project_prefix + \
        org_short_name].append(str(student_entity.user.account))
    print 'Student ' + str(student_entity.user.account) + \
        ' for ' + gc_project_prefix + org_short_name
    if gc_project_prefix + org_short_name not in mentors_by_orgs.keys():
      mentors_by_orgs[gc_project_prefix + org_short_name] = []
    mentors_by_orgs[gc_project_prefix + \
        org_short_name].append(str(mentor_entity.user.account))
    print 'Mentor ' + str(mentor_entity.user.account) + \
        ' for ' + gc_project_prefix + org_short_name
  
  roles_data = {}
  
  # prepare org admins data
  for org_key in org_admins_by_orgs.keys():
    for org_admin in org_admins_by_orgs[org_key]:
      roles_data[org_admin + '|' + org_key] = \
          {'role': 'project_owner', 
           'google_code_project_name': org_key, 
           'google_account': org_admin}

  # prepare mentors data
  for org_key in mentors_by_orgs.keys():
    for mentor in mentors_by_orgs[org_key]:
      if mentor + '|' + org_key not in roles_data.keys():
        roles_data[mentor + '|' + org_key] = \
            {'role': 'project_member', 
             'google_code_project_name': org_key, 
             'google_account': mentor}

  # prepare students data
  for org_key in students_by_orgs.keys():
    for student in students_by_orgs[org_key]:
      roles_data[student + '|' + org_key] = \
          {'role': 'project_member', 
           'google_code_project_name': org_key, 
           'google_account': student}
   
  data = []
  
  # add @gmail.com to all accounts that don't have @ in the account string
  # gmail.com is authorized domain for Google AppEngine that's why it's
  # missing
  for roles_key in roles_data.keys():
    if roles_data[roles_key]['google_account'].find('@') == -1:
      roles_data[roles_key]['google_account'] = \
        roles_data[roles_key]['google_account'] + '@gmail.com'
    data.append(roles_data[roles_key])
  
  export_fields = ['google_account', 'google_code_project_name', 'role']
  print 'Exporting the data to CSV'
  saveDataToCSV(csv_filename, data, export_fields)
  print "Exported Roles for Google Code to %s file." % csv_filename


def entityToDict(entity, field_names=None):
  """Returns a dict with all specified values of this entity.

  Args:
    entity: entity that will be converted to dictionary
    field_names: the fields that should be included, defaults to
      all fields that are of a type that is in DICT_TYPES.
  """
  from google.appengine.ext import db

  DICT_TYPES = (db.StringProperty, db.IntegerProperty)
  result = {}

  if not field_names:
    props = entity.properties().iteritems()
    field_names = [k for k, v in props if isinstance(v, DICT_TYPES)]

  for key in field_names:
    # Skip everything that is not valid
    if not hasattr(entity, key):
      continue

    result[key] = getattr(entity, key)

  if hasattr(entity, 'name'):
    name_prop = getattr(entity, 'name')
    if callable(name_prop):
      result['name'] = name_prop()

  return result


def surveyRecordCSVExport(csv_filename, survey_record_model, 
                          survey_model, survey_key):
  """CSV export for Survey Records for selected survey type and given survey key.
  
  Args:
    csv_filename: the name of the csv file to save
    survey_record_model: model of surver record that will be exported
    survey_model: model of the survey that wil be exported
    survey_key: key of the survey that records will be exported
  """
  from soc.models.project_survey import ProjectSurvey
  from soc.models.grading_project_survey import GradingProjectSurvey

  # fetch survey
  survey = survey_model.get(survey_key)

  if not survey:
    print "Survey of given model and key doesn't exist."
    return

  schema = eval(survey.survey_content.schema)
  ordered_properties = survey.survey_content.orderedProperties()

  getSurveyRecords = getEntities(survey_record_model)
  survey_records = getSurveyRecords()
  survey_records_amount = len(survey_records)
  print "Fetched %d Survey Records." % survey_records_amount

  count = 0

  print "Preparing SurveyRecord data for export."

  sr_key = {}
  comments_properties = []
  for property_name in ordered_properties:
    sr_key[property_name] = schema[property_name]['question']
    if schema[property_name]['has_comment']:
      sr_key['comment_for_' + property_name] = 'None'
      comments_properties.append('comment_for_' + property_name)

  for comment in comments_properties:
    ordered_properties.append(comment)

  survey_record_data = []
  for i in survey_records.keys():
    if str(survey_records[i].survey.key()) != survey_key:
        continue
    data = entityToDict(survey_records[i], ordered_properties)

    if (survey_model == GradingProjectSurvey) or \
        (survey_model == ProjectSurvey):
      data['organization'] = survey_records[i].org.name
      data['project_title'] = survey_records[i].project.title
      data['user_link_id'] = survey_records[i].user.link_id

      if survey_model == GradingProjectSurvey:
        data['project_grade'] = survey_records[i].grade

    survey_record_data.append(data)

    count += 1
    print str(count) + '/' + str(survey_records_amount) + ' ' + str(i)

  if (survey_model == GradingProjectSurvey) or (survey_model == ProjectSurvey):
    ordered_properties.append('organization')
    ordered_properties.append('project_title')
    ordered_properties.append('user_link_id')
    sr_key['organization'] = 'None'
    sr_key['project_title'] = 'None'
    sr_key['user_link_id'] = 'None'

    if survey_model == GradingProjectSurvey:
      ordered_properties.append('project_grade')
      sr_key['project_grade'] = 'None'

  survey_record_data.insert(0, sr_key)

  saveDataToCSV(csv_filename, survey_record_data, ordered_properties)
  print "Survey Records exported to %s file." % csv_filename


def main(args):
  """Main routine.
  """

  interactive.setup()

  from soc.models.organization import Organization
  from soc.models.user import User
  from soc.models.student import Student
  from soc.models.mentor import Mentor
  from soc.models.org_admin import OrgAdmin
  from soc.models.job import Job
  from soc.models.student_proposal import StudentProposal
  from soc.models.student_project import StudentProject

  def slotSaver(org, value):
    org.slots = value
  def popSaver(org, value):
    org.nr_applications = value
  def rawSaver(org, value):
    org.slots_calculated = value

  context = {
      'load': loadPickle,
      'dump': dumpPickle,
      'orgStats': orgStats,
      'printPopularity': printPopularity,
      'saveValues': saveValues,
      'getEntities': getEntities,
      'deleteEntities': deleteEntities,
      'getOrgs': getEntities(Organization),
      'getUsers': getEntities(User),
      'getStudents': getEntities(Student),
      'getMentors': getEntities(Mentor),
      'getOrgAdmins': getEntities(OrgAdmin),
      'getStudentProjects': getEntities(StudentProject),
      'getProps': getProps,
      'countStudentsWithProposals': countStudentsWithProposals,
      'setOrganizationInSurveyRecords': setOrganizationInSurveyRecords,
      'convertProposals': convertProposals,
      'addFollower': addFollower,
      'Organization': Organization,
      'Job': Job,
      'User': User,
      'Student': Student,
      'Mentor': Mentor,
      'OrgAdmin': OrgAdmin,
      'StudentProject': StudentProject,
      'StudentProposal': StudentProposal,
      'slotSaver': slotSaver,
      'popSaver': popSaver,
      'rawSaver': rawSaver,
      'startSpam': startSpam,
      'reviveJobs': reviveJobs,
      'deidleJobs': deidleJobs,
      'exportStudentsWithProjects': exportStudentsWithProjects,
      'exportUniqueOrgAdminsAndMentors': exportUniqueOrgAdminsAndMentors,
      'exportOrgsForGoogleCode': exportOrgsForGoogleCode,
      'exportRolesForGoogleCode': exportRolesForGoogleCode,
      'startUniqueUserIdConversion': startUniqueUserIdConversion,
      'surveyRecordCSVExport': surveyRecordCSVExport,
  }

  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:])