import settings import pickle from askbot import models from askbot.conf import settings as askbot_settings from askbot.utils.console import ProgressBar from askbot.utils.slug import slugify from django.conf import settings as django_settings from django.core.management.base import BaseCommand, CommandError from django.db import transaction from django.forms import EmailField, ValidationError from datetime import datetime from django.db.utils import IntegrityError from django.utils import translation import sys from launchpadlib.launchpad import Launchpad from launchpadlib.uris import LPNET_SERVICE_ROOT def no_credential(): print "Can't proceed without Launchpad credential." sys.exit() """Logs into Launchpad """ #cachedir = '/Users/evgenyfadeev/.launchadlib/cache' launchpad = Launchpad.login_with( 'Extract Answers', version='devel', credential_save_failed=no_credential ) user_mapping = {} def get_questions(project_name): """Retrieves all questions in project_name on Launchpad""" project = launchpad.projects[project_name] return project.searchQuestions() def get_user_data(user_link): """returns dictionary with keys: * username * confirmed_email_addresses """ # check out user cache first if user_link in user_mapping: return user_mapping[user_link] username = user_link.split('~')[1] user_data = { 'username': username, 'confirmed_email_addresses': list() } lp_user = launchpad.people[username] for email in lp_user.confirmed_email_addresses: # search for the user based on their email email = str(email).split('/')[-1] user_data['confirmed_email_addresses'].append(email) user_mapping[user_link] = user_data return user_data def get_or_create_user(user_data): """returns Askbot user. If user corresponding to the given data does not exist, it is created """ username = user_data['username'] #check the cache by user name if username in user_mapping: return user_mapping[username] try: # find using identical username first user = models.User.objects.get(username=username) except models.User.DoesNotExist: # we haven't created the user yet try: user = models.User.objects.filter(email__in=user_data['confirmed_email_addresses'])[0] except: user = models.User(username=username) if len(user_data['confirmed_email_addresses']): user.email = user_data['confirmed_email_addresses'][0] user.save() # cache the users we've seen so far to avoid API calls user_mapping[username] = user return user def save_questions(questions, project_name, data_filename): """gets data from the launchpad answers and then saves it in the python pickled format so that the data can be uploaded elsewhere """ #create data file if not exists data_file = open(data_filename, 'a+') data_file.close() #read the data file try: data_file = open(data_filename, 'r') question_data = pickle.load(data_file) data_file.close() except EOFError: question_data = dict() try: for question in questions: print '"' + question.title + '",' + str(question.date_created) if question.self_link in question_data: continue try: responses = question.messages_collection.entries print str(len(responses)) except AttributeError: print "No Answers for question" + str(question) responses = None question_datum = { 'owner': get_user_data(question.owner_link), 'self_link': question.self_link, 'title': question.title, 'body_text': question.description, 'timestamp': question.date_created.replace(tzinfo=None), 'tags': project_name + ' migrated' } question_data[question.self_link] = question_datum answer_data = list() for response in responses: try: timestamp=datetime.strptime(response['date_created'][0:-6], '%Y-%m-%dT%H:%M:%S.%f') except ValueError: #some timestamps don't have the millisectons, thanks LP! timestamp=datetime.strptime(response['date_created'][0:-6], '%Y-%m-%dT%H:%M:%S') if 'content' in response and len(response['content']) > 1: #for some reason, Launchpad allows blank answers answer = { 'owner': get_user_data(response['owner_link']), 'body_text': response['content'], 'timestamp': timestamp } answer_data.append(answer) question_datum['responses'] = answer_data finally: data_file = open(data_filename, 'w') pickle.dump(question_data, data_file) data_file.close() def import_questions(data_filename): """loops through all items in launchpad Question format, and adds them as askbot Questions and Answers""" status_file = open('write.status', 'a') try: import_log = pickle.load(status_file) if not isinstance(import_log, dict): import_log = {} except: import_log = {} data_file = open(data_filename, 'r') questions = pickle.load(data_file) for question in questions.values(): print '"' + question['title'] + '",' + str(question['timestamp']) try: responses = question['responses'] print str(len(responses)) except AttributeError: responses = None print "No Answers" if question['self_link'] in import_log: print "Already imported - skipping the above question" continue # post the question question_user = get_or_create_user(question['owner']) try: ab_question = question_user.post_question( title=question['title'], body_text=question['body_text'], timestamp=question['timestamp'], tags=question['tags'] ) except IntegrityError: # the question already exists, but we didn't find it somehow print "Had an IntegrityError" continue for response in question['responses']: if len(response['body_text']) == 0: continue response_user = get_or_create_user(response['owner']) #for some reason, Launchpad allows blank answers answer = response_user.post_answer( question=ab_question, body_text=response['body_text'], timestamp=response['timestamp'] ) import_log[question['self_link']] = 1 #mark as imported status_file.close() status_file = open('write.status', 'w') pickle.dump(import_log, status_file) def main_read(): questions = get_questions('nova') save_questions(questions, 'nova', 'launchpad.dat') print str(len(questions)) + " found" def main_write(): translation.activate('en') setting_backup = askbot_settings.LIMIT_ONE_ANSWER_PER_USER askbot_settings.update('LIMIT_ONE_ANSWER_PER_USER', False) import_questions('launchpad.dat') askbot_settings.update('LIMIT_ONE_ANSWER_PER_USER', setting_backup)