<commit_before># vim: set ai ts=4 sw=4 et:

from mysite.search.models import Project, Bug, get_image_data_scaled
import mysite.customs.models
from mysite.customs import ohloh
import mysite.profile.controllers
import mysite.base.unicode_sanity

import django
from django.db import models
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
from django.conf import settings
from django.contrib.auth import SESSION_KEY, BACKEND_SESSION_KEY, load_backend
from django.core.urlresolvers import reverse
from django.core.cache import cache
import django.db.models.query

import datetime
import sys
import uuid
import urllib
import random
import collections
import simplejson
import re

DEFAULT_LOCATION='Inaccessible Island'

def url2printably_short(url, CUTOFF=50):
    short_enough_pieces_so_far = []
    die_next = False
    wrappable_characters = "/"
    for url_piece in url.split(wrappable_characters):
        if die_next:
            return '/'.join(short_enough_pieces_so_far)

        # Logic: If this URL piece is longer than CUTOFF, then stop appending
        # and return.
        if len(url_piece) > CUTOFF:
            url_piece = url_piece[:CUTOFF-3] + '...'
            die_next = True
        # always append
        short_enough_pieces_so_far.append(url_piece)
    return '/'.join(short_enough_pieces_so_far)

def generate_person_photo_path(instance, filename, suffix=""):
    random_uuid = uuid.uuid4()
    return random_uuid.hex + suffix

class RepositoryCommitter(models.Model):
    """Ok, so we need to keep track of repository committers, e.g.
        <EMAIL>@<EMAIL>
    That's because when a user says, 'oy, this data you guys imported isn't
    mine', what she or he is typically saying is something like
    'Don't give me any more data from Ohloh pertaining to this dude named
    <EMAIL> checking code into F-Spot.'"""
    project = models.ForeignKey(Project)
    data_import_attempt = models.ForeignKey('DataImportAttempt')

    def committer_identifier(self):
        return self.data_import_attempt.committer_identifier

    def source(self):
        return self.data_import_attempt.source

    class Meta:
        unique_together = ('project', 'data_import_attempt')

class Person(models.Model):
    """ A human bean. """
    # {{{
    homepage_url = models.URLField(default="", blank=True)
    user = models.ForeignKey(User, unique=True)
    gotten_name_from_ohloh = models.BooleanField(default=False)
    interested_in_working_on = models.CharField(max_length=1024, default='') # FIXME: Ditch this.
    last_polled = models.DateTimeField(default=datetime.datetime(1970, 1, 1))
    show_email = models.BooleanField(default=False)
    bio = models.TextField(blank=True) 
    contact_blurb = models.TextField(blank=True)
    expand_next_steps = models.BooleanField(default=True)
    photo = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b),
                              default='')
    photo_thumbnail = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b, suffix="-thumbnail"),
                              default='',
                              null=True)

    photo_thumbnail_30px_wide = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b, suffix="-thumbnail-30px-wide"),
                              default='', null=True)

    photo_thumbnail_20px_wide = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b, suffix="-thumbnail-20px-wide"),
                              default='', null=True)

    blacklisted_repository_committers = models.ManyToManyField(RepositoryCommitter)
    dont_guess_my_location = models.BooleanField(default=False)
    location_confirmed = models.BooleanField(default=False)
    location_display_name = models.CharField(max_length=255, blank=True,
                                             verbose_name='Location')

    def location_is_public(self):
        return self.location_confirmed and self.location_display_name

    def reindex_for_person_search(self):
        import mysite.profile.tasks
        task = mysite.profile.tasks.ReindexPerson()
        task.delay(person_id=self.id)

    def get_public_location_or_default(self):
        if self.location_is_public():
            return self.location_display_name
        else:
            return DEFAULT_LOCATION
    
    def __unicode__(self):
        return "username: %s, name: %s %s" % (self.user.username,
                self.user.first_name, self.user.last_name)

    def get_photo_url_or_default(self):
        try:
            return self.photo.url
        except ValueError:
            return '/static/images/profile-photos/penguin.png'

    @staticmethod
    def get_from_session_key(session_key):
        '''Based almost entirely on
        http://www.djangosnippets.org/snippets/1276/
        Thanks jdunck!'''

        session_engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
        session_wrapper = session_engine.SessionStore(session_key)
        user_id = session_wrapper.get(SESSION_KEY)
        auth_backend = load_backend(
                session_wrapper.get(BACKEND_SESSION_KEY))

        if user_id and auth_backend:
            return Person.objects.get(user=auth_backend.get_user(user_id))
        else:
            return None

    def get_photo_thumbnail_url_or_default(self):
        try:
            return self.photo_thumbnail.url
        except ValueError:
            return '/static/images/profile-photos/penguin-40px.png'

    def get_photo_thumbnail_width(self):
        try:
            return self.photo_thumbnail.width
        except ValueError:
            return 40

    def get_photo_thumbnail_height(self):
        try:
            return self.photo_thumbnail.height
        except ValueError:
            return 51

    def get_photo_thumbnail_30px_wide_url_or_default(self):
        try:
            return self.photo_thumbnail_30px_wide.url
        except ValueError:
            return '/static/images/profile-photos/penguin-30px.png'

    def get_photo_thumbnail_20px_wide_url_or_default(self):
        try:
            return self.photo_thumbnail_20px_wide.url
        except ValueError:
            return '/static/images/profile-photos/penguin-20px.png'

    def get_photo_thumbnail_width_20px(self):
        try:
            return self.photo_thumbnail_20px_wide.width
        except ValueError:
            return 20

    def get_photo_thumbnail_height_20px(self):
        try:
            return self.photo_thumbnail_20px_wide.height
        except ValueError:
            return 20

    def get_published_portfolio_entries(self):
        return PortfolioEntry.objects.filter(person=self, is_published=True, is_deleted=False)

    def get_cache_key_for_projects(self):
        return 'projects_for_person_with_pk_%d_v2' % self.pk

    @mysite.base.decorators.cache_method('get_cache_key_for_projects')
    def get_list_of_project_names(self):
        return self.get_published_portfolio_entries().values_list(
                'project__name', flat=True).distinct()[:]

    @staticmethod
    def only_terms_with_results(terms):
        # Remove terms whose hit counts are zero.
        terms_with_results = [] 
        for term in terms:
            query = mysite.search.controllers.Query(terms=[term])
            hit_count = query.get_or_create_cached_hit_count()
            if hit_count != 0:
                terms_with_results.append(term)
        return terms_with_results

    def get_recommended_search_terms(self):
        # {{{<commit_msg>get_list_of_projects now returns a list.<commit_after># vim: set ai ts=4 sw=4 et:

from mysite.search.models import Project, Bug, get_image_data_scaled
import mysite.customs.models
from mysite.customs import ohloh
import mysite.profile.controllers
import mysite.base.unicode_sanity

import django
from django.db import models
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
from django.conf import settings
from django.contrib.auth import SESSION_KEY, BACKEND_SESSION_KEY, load_backend
from django.core.urlresolvers import reverse
from django.core.cache import cache
import django.db.models.query

import datetime
import sys
import uuid
import urllib
import random
import collections
import simplejson
import re

DEFAULT_LOCATION='Inaccessible Island'

def url2printably_short(url, CUTOFF=50):
    short_enough_pieces_so_far = []
    die_next = False
    wrappable_characters = "/"
    for url_piece in url.split(wrappable_characters):
        if die_next:
            return '/'.join(short_enough_pieces_so_far)

        # Logic: If this URL piece is longer than CUTOFF, then stop appending
        # and return.
        if len(url_piece) > CUTOFF:
            url_piece = url_piece[:CUTOFF-3] + '...'
            die_next = True
        # always append
        short_enough_pieces_so_far.append(url_piece)
    return '/'.join(short_enough_pieces_so_far)

def generate_person_photo_path(instance, filename, suffix=""):
    random_uuid = uuid.uuid4()
    return random_uuid.hex + suffix

class RepositoryCommitter(models.Model):
    """Ok, so we need to keep track of repository committers, e.g.
        <EMAIL>
    That's because when a user says, 'oy, this data you guys imported isn't
    mine', what she or he is typically saying is something like
    'Don't give me any more data from Ohloh pertaining to this dude named
    <EMAIL> checking code into F-Spot.'"""
    project = models.ForeignKey(Project)
    data_import_attempt = models.ForeignKey('DataImportAttempt')

    def committer_identifier(self):
        return self.data_import_attempt.committer_identifier

    def source(self):
        return self.data_import_attempt.source

    class Meta:
        unique_together = ('project', 'data_import_attempt')

class Person(models.Model):
    """ A human bean. """
    # {{{
    homepage_url = models.URLField(default="", blank=True)
    user = models.ForeignKey(User, unique=True)
    gotten_name_from_ohloh = models.BooleanField(default=False)
    interested_in_working_on = models.CharField(max_length=1024, default='') # FIXME: Ditch this.
    last_polled = models.DateTimeField(default=datetime.datetime(1970, 1, 1))
    show_email = models.BooleanField(default=False)
    bio = models.TextField(blank=True) 
    contact_blurb = models.TextField(blank=True)
    expand_next_steps = models.BooleanField(default=True)
    photo = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b),
                              default='')
    photo_thumbnail = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b, suffix="-thumbnail"),
                              default='',
                              null=True)

    photo_thumbnail_30px_wide = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b, suffix="-thumbnail-30px-wide"),
                              default='', null=True)

    photo_thumbnail_20px_wide = models.ImageField(upload_to=
                              lambda a, b: 'static/photos/profile-photos/' + 
                              generate_person_photo_path(a, b, suffix="-thumbnail-20px-wide"),
                              default='', null=True)

    blacklisted_repository_committers = models.ManyToManyField(RepositoryCommitter)
    dont_guess_my_location = models.BooleanField(default=False)
    location_confirmed = models.BooleanField(default=False)
    location_display_name = models.CharField(max_length=255, blank=True,
                                             verbose_name='Location')

    def location_is_public(self):
        return self.location_confirmed and self.location_display_name

    def reindex_for_person_search(self):
        import mysite.profile.tasks
        task = mysite.profile.tasks.ReindexPerson()
        task.delay(person_id=self.id)

    def get_public_location_or_default(self):
        if self.location_is_public():
            return self.location_display_name
        else:
            return DEFAULT_LOCATION
    
    def __unicode__(self):
        return "username: %s, name: %s %s" % (self.user.username,
                self.user.first_name, self.user.last_name)

    def get_photo_url_or_default(self):
        try:
            return self.photo.url
        except ValueError:
            return '/static/images/profile-photos/penguin.png'

    @staticmethod
    def get_from_session_key(session_key):
        '''Based almost entirely on
        http://www.djangosnippets.org/snippets/1276/
        Thanks jdunck!'''

        session_engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
        session_wrapper = session_engine.SessionStore(session_key)
        user_id = session_wrapper.get(SESSION_KEY)
        auth_backend = load_backend(
                session_wrapper.get(BACKEND_SESSION_KEY))

        if user_id and auth_backend:
            return Person.objects.get(user=auth_backend.get_user(user_id))
        else:
            return None

    def get_photo_thumbnail_url_or_default(self):
        try:
            return self.photo_thumbnail.url
        except ValueError:
            return '/static/images/profile-photos/penguin-40px.png'

    def get_photo_thumbnail_width(self):
        try:
            return self.photo_thumbnail.width
        except ValueError:
            return 40

    def get_photo_thumbnail_height(self):
        try:
            return self.photo_thumbnail.height
        except ValueError:
            return 51

    def get_photo_thumbnail_30px_wide_url_or_default(self):
        try:
            return self.photo_thumbnail_30px_wide.url
        except ValueError:
            return '/static/images/profile-photos/penguin-30px.png'

    def get_photo_thumbnail_20px_wide_url_or_default(self):
        try:
            return self.photo_thumbnail_20px_wide.url
        except ValueError:
            return '/static/images/profile-photos/penguin-20px.png'

    def get_photo_thumbnail_width_20px(self):
        try:
            return self.photo_thumbnail_20px_wide.width
        except ValueError:
            return 20

    def get_photo_thumbnail_height_20px(self):
        try:
            return self.photo_thumbnail_20px_wide.height
        except ValueError:
            return 20

    def get_published_portfolio_entries(self):
        return PortfolioEntry.objects.filter(person=self, is_published=True, is_deleted=False)

    def get_cache_key_for_projects(self):
        return 'projects_for_person_with_pk_%d_v2' % self.pk

    @mysite.base.decorators.cache_method('get_cache_key_for_projects')
    def get_list_of_project_names(self):
        return list(self.get_published_portfolio_entries().values_list(
                'project__name', flat=True).distinct())

    @staticmethod
    def only_terms_with_results(terms):
        # Remove terms whose hit counts are zero.
        terms_with_results = [] 
        for term in terms:
            query = mysite.search.controllers.Query(terms=[term])
            hit_count = query.get_or_create_cached_hit_count()
            if hit_count != 0:
                terms_with_results.append(term)
        return terms_with_results

    def get_recommended_search_terms(self):
        # {{{
{'fraction_non_alphanumeric': 0.08360552763819096, 'fraction_numerical': 0.008040201005025126, 'mean_word_length': 2.633272478320402, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3916004', 'n_tokens_mistral': 4755, 'n_tokens_neox': 4545, 'n_words': 922}