<commit_before># This file is part of ExponWords.
#
# ExponWords is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# ExponWords is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# ExponWords.  If not, see <http://www.gnu.org/licenses/>.

# Copyright (C) 2011 Csaba Hoch

import datetime
import random
import re
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _

version = '0.8.0'

class WDict(models.Model):

    # WDict = word dictionary (as opposed to the dictionary data type which is
    # an "object dictionary")

    user = models.ForeignKey(User)
    name = models.CharField(max_length=255) # the name of the dictionary
    lang1 = models.CharField(max_length=255)
    lang2 = models.CharField(max_length=255)
    deleted = models.BooleanField(default=False)

    def __unicode__(self):
        return self.name

    def get_words_to_practice_today(self):
        today = datetime.date.today()
        result = []
        for wp in self.wordpair_set.filter(deleted=False):
            if wp.date1 <= today:
                result.append((wp, 1))
            if wp.date2 <= today:
                result.append((wp, 2))
        random.shuffle(result)
        return result

class WordPair(models.Model):

    # each word pair belongs to a dictionary
    wdict = models.ForeignKey(WDict)

    # the word in the first/second language:
    word_in_lang1 = models.CharField(max_length=255)
    word_in_lang2 = models.CharField(max_length=255)

    # strengths of the word
    strength1 = models.IntegerField(default=0)
    strength2 = models.IntegerField(default=0)

    # dates of the next practice
    date_added = models.DateField()
    date1 = models.DateField()
    date2 = models.DateField()

    # explanation, examples, comments, etc.
    explanation = models.TextField(blank=True)

    # labels
    labels = models.CharField(max_length=255, blank=True)

    # whether the word pair is deleted or not
    deleted = models.BooleanField(default=False)

    def save(self):
        self.normalize()
        return models.Model.save(self)

    def normalize(self):
        self.word_in_lang1 = self.word_in_lang1.strip()
        self.word_in_lang2 = self.word_in_lang2.strip()
        self.explanation = self.explanation.rstrip()
        self.normalize_labels()

    def __unicode__(self):
        return ('<%s -- %s>' %
                (repr(self.word_in_lang1), repr(self.word_in_lang2)))

    def get_strength(self, direction):
        if direction == 1:
            return self.strength1
        else:
            return self.strength2

    def set_strength(self, direction, value):
        if direction == 1:
            self.strength1 = value
        else:
            self.strength2 = value

    def get_date(self, direction):
        if direction == 1:
            return self.date1
        else:
            return self.date2

    def set_date(self, direction, value):
        if direction == 1:
            self.date1 = value
        else:
            self.date2 = value

    @staticmethod
    def next_date(strength, date):
        if strength < 0:
            strength = 0
        return date + datetime.timedelta(2 ** strength)

    def strengthen(self, direction):
        strength = self.get_strength(direction)
        self.set_date(direction,
                      self.next_date(strength, datetime.date.today()))
        self.set_strength(direction, self.get_strength(direction) + 1)

    def weaken(self, direction):
        self.set_date(direction, datetime.date.today())
        new_strength = min(self.get_strength(direction), 0)
        self.set_strength(direction, new_strength)

    @staticmethod
    def get_label_set_from_str(s):
        return set(unicode(s).split())

    def get_label_set(self):
        return self.get_label_set_from_str(self.labels)

    def set_label_set(self, label_set):
        self.labels = ' '.join(sorted(label_set))

    def normalize_labels(self):
        self.set_label_set(self.get_label_set())

    def add_labels(self, labels):
        self.set_label_set(self.get_label_set() |
                           self.get_label_set_from_str(labels))

    def remove_labels(self, labels):
        self.set_label_set(self.get_label_set() -
                           self.get_label_set_from_str(labels))

    def set_labels(self, labels):
        self.set_label_set(self.get_label_set_from_str(labels))

    @staticmethod
    def get_fields_to_be_edited():
        return ('word_in_lang1',
                'word_in_lang2',
                'explanation',
                'labels',
                'date_added',
                'date1',
                'date2',
                'strength1',
                'strength2')

    @staticmethod
    def get_fields_to_be_saved():
        return ('labels',
                'date1',
                'date2',
                'strength1',
                'strength2')

    def get_saved_fields(self):
        saved_fields = {}
        for field in self.get_fields_to_be_saved():
            saved_fields[field] = getattr(self, field)
        return saved_fields

class EWException(Exception):
    """A very simple exception class used."""

    def __init__(self, value):
        """Constructor.

        **Argument:**

        - `value` (object) -- The reason of the error.
        """
        Exception.__init__(self)
        self.value = value

    def __unicode__(self):
        """Returns the string representation of the error reason.

        **Returns:** str
        """

        value = self.value
        if isinstance(value, unicode):
            return value
        elif isinstance(value, str):
            return unicode(value)
        else:
            return repr(value)

def create_add_word_pairs(wdict, word_pairs):
    for wp in word_pairs:
        wdict.wordpair_set.add(wp)
        wp.save()
        wdict.save()

def get_labels(user):
    all_word_pairs = WordPair.objects.filter(wdict__user=user,
                                             wdict__deleted=False,
                                             deleted=False)
    labels = set()
    for wp in all_word_pairs:
        labels.update(unicode(wp.labels).split())
    return labels

def import_textfile(s, wdict):
    """Adds words from a text file to a dictionary.

    Arguments:
    - s (str)
    - wdict (WDict)
    """

    i = 1
    word_pairs = []
    for line in s.splitlines():
        line = line.rstrip()
        if (line == '') or (line[0] == ' '):
            # This line is part of an explanation.
            if len(word_pairs) != 0:
                line = re.sub('^ {1,4}', '', line) # removing prefix spaces
                word_pairs[-1].explanation += line + '\n'
            elif line == '':
                pass
            else:
                msg = (_('Line %(linenumber)s should not have spaces in '
                         'the beginning: %(line)s') %
                       {'linenumber': i, 'line': line})
                raise EWException(msg)
        else:
            # This line contains a word pair.
            strength_date_regexp = '<(-?\d+) +(\d\d\d\d)-(\d\d)-(\d\d)>'
            regexp = (r'^(\{(\d+)\})? *(.*?) -- (.*?)' +
                      '( ' + strength_date_regexp * 2 + ')?' +
                      '$')
            r = re.search(regexp, line)
            if r is None:
                msg = (_('Line %(linenumber)s is incorrect: %(line)s') %
                       {'linenumber': i, 'line': line})
                raise EWException(msg)

            wp = WordPair()
            word_pairs.append(wp)

            wp.word_in_lang1 = r.group(3)
            wp.word_in_lang2 = r.group(4)
            wp.explanation = ''
            if r.group(5) is not None:
                wp.date_added = datetime.date.today()
                wp.date1 = datetime.date(int(r.group(7)),
                                         int(r.group(8)),
                                         int(r.group(9)))
                wp.date2 = datetime.date(int(r.group(11)),
                                         int(r.group(12)),
                                         int(r.group(13)))
                wp.strength1 = int(r.group(6))
                wp.strength2 = int(r.group(10))
            else:
                wp.date_added = datetime.date.today()
                wp.date1 = datetime.date.today()
                wp.date2 = datetime.date.today()
                wp.strength1 = 0
                wp.strength2 = 0

        i += 1

    create_add_word_pairs(wdict, word_pairs)
    return word_pairs

def import_tsv(s, wdict):
    """Adds words from a text of tab-separeted values to a dictionary.

    Arguments:
    - s (str)
    - wdict (WDict)
    """

    i = 1
    word_pairs = []
    for line in s.splitlines():
        line = line.strip()
        if (line == ''):
            continue

        fields = line.split('\t')
        if len(fields) < 2:
            msg = (_('Not enough fields in line %(linenumber)s: %(line)s') %
                   {'linenumber': i, 'line': line})
            raise EWException(msg)
        elif 2 <= len(fields) <= 3:
            wp = WordPair()
            wp.word_in_lang1 = fields[0]
            wp.word_in_lang2 = fields[1]
            if len(fields) == 3:
                wp.explanation = fields[2]
            wp.date1 = datetime.date.today()
            wp.date2 = datetime.date.today()
            wp.date_added = datetime.date.today()
            word_pairs.append(wp)
        else:
            msg = (_('Too many fields in line %(linenumber)s: %(line)s') %
                   {'linenumber': i, 'line': line})
            raise EWException(msg)

        i += 1

    create_add_word_pairs(wdict, word_pairs)
    return word_pairs

def export_textfile(wdict):
    """Prints a dictionary in the old text format.

    Arguments:
    - wdict (WDict)

    Returns: str
    """

    result = []
    for wp in wdict.wordpair_set.filter(deleted=False):
        result.append(
            '%s -- %s <%s %s><%s %s>\n' %
            (wp.word_in_lang1,
             wp.word_in_lang2,
             str(wp.strength1),
             str(wp.date1),
             str(wp.strength2),
             str(wp.date2)))
        for expl_line in wp.explanation.splitlines():
            if expl_line != '':
                result.append('    ')
                result.append(expl_line)
            result.append('\n')
    return ''.join(result)

class EWLogEntry(models.Model):

    datetime = models.DateTimeField()
    action = models.TextField()
    user = models.ForeignKey(User, blank=True, null=True)
    username = models.TextField(blank=True)
    text = models.TextField(blank=True)
    ipaddress = models.TextField(blank=True)

def log(request, action, text=''):

    logentry = EWLogEntry()
    logentry.datetime = datetime.datetime.now()
    try:
        logentry.action = action
        logentry.ipaddress = (request.META.get('REMOTE_ADDR' , '') + ', ' +
                              request.META.get('HTTP_X_FORWARDED_FOR', ''))
        if request.user.is_authenticated():
            logentry.user = request.user
            logentry.username = request.user.username

        logentry.text = text
    except Exception, e:
        logentry.action = 'Logging failed'
    logentry.save()

def parse_date(s):
    return datetime.datetime.strptime(s, '%Y-%m-%d')

##### show future #####

def incr_wcd(wcd, wdict, strength, date, count):
    strength_to_word_count = wcd.setdefault((wdict, date), {})
    try:
        strength_to_word_count[strength] += count
    except KeyError:
        strength_to_word_count[strength] = count

def get_initial_word_counts_dict(user, start_date):
    """
    Returns: wdicts, {(wdict, date): {strength: word_count}}
    """

    def add_wp(wcd, wdict, strength, date):
        if (start_date is not None) and (date < start_date):
            date = start_date
        incr_wcd(wcd, wdict, strength, date, 1)

    wcd = {}
    wdicts = WDict.objects.filter(user=user, deleted=False)
    word_pairs = WordPair.objects.filter(wdict__user=user,
                                         wdict__deleted=False,
                                         deleted=False)
    for wp in word_pairs:
        add_wp(wcd, wp.wdict, wp.strength1, wp.date1)
        add_wp(wcd, wp.wdict, wp.strength2, wp.date2)
    return wdicts, wcd

def calc_future(user, days_count, start_date):
    """
    Returns: [date], [WDict], {(WDict, date): question_count}
    """

    dates = [start_date + datetime.timedelta(i)
             for i in range(days_count)]

    wdicts, wcd = get_initial_word_counts_dict(user, start_date)

    date_to_question_count = {} # {(wdict, date): question_count}
    for date in dates:
        for wdict in wdicts:
            strength_to_word_count = wcd.pop((wdict, date), {})
            question_count = 0
            for strength, word_count in strength_to_word_count.items():
                question_count += word_count
                new_date = WordPair.next_date(strength, date)
                incr_wcd(wcd, wdict, strength + 1, new_date, word_count)
            date_to_question_count[(wdict, date)] = question_count

    return dates, wdicts, date_to_question_count
<commit_msg>Version set to 0.8.1<commit_after># This file is part of ExponWords.
#
# ExponWords is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# ExponWords is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# ExponWords.  If not, see <http://www.gnu.org/licenses/>.

# Copyright (C) 2011 Csaba Hoch

import datetime
import random
import re
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _

version = '0.8.1'

class WDict(models.Model):

    # WDict = word dictionary (as opposed to the dictionary data type which is
    # an "object dictionary")

    user = models.ForeignKey(User)
    name = models.CharField(max_length=255) # the name of the dictionary
    lang1 = models.CharField(max_length=255)
    lang2 = models.CharField(max_length=255)
    deleted = models.BooleanField(default=False)

    def __unicode__(self):
        return self.name

    def get_words_to_practice_today(self):
        today = datetime.date.today()
        result = []
        for wp in self.wordpair_set.filter(deleted=False):
            if wp.date1 <= today:
                result.append((wp, 1))
            if wp.date2 <= today:
                result.append((wp, 2))
        random.shuffle(result)
        return result

class WordPair(models.Model):

    # each word pair belongs to a dictionary
    wdict = models.ForeignKey(WDict)

    # the word in the first/second language:
    word_in_lang1 = models.CharField(max_length=255)
    word_in_lang2 = models.CharField(max_length=255)

    # strengths of the word
    strength1 = models.IntegerField(default=0)
    strength2 = models.IntegerField(default=0)

    # dates of the next practice
    date_added = models.DateField()
    date1 = models.DateField()
    date2 = models.DateField()

    # explanation, examples, comments, etc.
    explanation = models.TextField(blank=True)

    # labels
    labels = models.CharField(max_length=255, blank=True)

    # whether the word pair is deleted or not
    deleted = models.BooleanField(default=False)

    def save(self):
        self.normalize()
        return models.Model.save(self)

    def normalize(self):
        self.word_in_lang1 = self.word_in_lang1.strip()
        self.word_in_lang2 = self.word_in_lang2.strip()
        self.explanation = self.explanation.rstrip()
        self.normalize_labels()

    def __unicode__(self):
        return ('<%s -- %s>' %
                (repr(self.word_in_lang1), repr(self.word_in_lang2)))

    def get_strength(self, direction):
        if direction == 1:
            return self.strength1
        else:
            return self.strength2

    def set_strength(self, direction, value):
        if direction == 1:
            self.strength1 = value
        else:
            self.strength2 = value

    def get_date(self, direction):
        if direction == 1:
            return self.date1
        else:
            return self.date2

    def set_date(self, direction, value):
        if direction == 1:
            self.date1 = value
        else:
            self.date2 = value

    @staticmethod
    def next_date(strength, date):
        if strength < 0:
            strength = 0
        return date + datetime.timedelta(2 ** strength)

    def strengthen(self, direction):
        strength = self.get_strength(direction)
        self.set_date(direction,
                      self.next_date(strength, datetime.date.today()))
        self.set_strength(direction, self.get_strength(direction) + 1)

    def weaken(self, direction):
        self.set_date(direction, datetime.date.today())
        new_strength = min(self.get_strength(direction), 0)
        self.set_strength(direction, new_strength)

    @staticmethod
    def get_label_set_from_str(s):
        return set(unicode(s).split())

    def get_label_set(self):
        return self.get_label_set_from_str(self.labels)

    def set_label_set(self, label_set):
        self.labels = ' '.join(sorted(label_set))

    def normalize_labels(self):
        self.set_label_set(self.get_label_set())

    def add_labels(self, labels):
        self.set_label_set(self.get_label_set() |
                           self.get_label_set_from_str(labels))

    def remove_labels(self, labels):
        self.set_label_set(self.get_label_set() -
                           self.get_label_set_from_str(labels))

    def set_labels(self, labels):
        self.set_label_set(self.get_label_set_from_str(labels))

    @staticmethod
    def get_fields_to_be_edited():
        return ('word_in_lang1',
                'word_in_lang2',
                'explanation',
                'labels',
                'date_added',
                'date1',
                'date2',
                'strength1',
                'strength2')

    @staticmethod
    def get_fields_to_be_saved():
        return ('labels',
                'date1',
                'date2',
                'strength1',
                'strength2')

    def get_saved_fields(self):
        saved_fields = {}
        for field in self.get_fields_to_be_saved():
            saved_fields[field] = getattr(self, field)
        return saved_fields

class EWException(Exception):
    """A very simple exception class used."""

    def __init__(self, value):
        """Constructor.

        **Argument:**

        - `value` (object) -- The reason of the error.
        """
        Exception.__init__(self)
        self.value = value

    def __unicode__(self):
        """Returns the string representation of the error reason.

        **Returns:** str
        """

        value = self.value
        if isinstance(value, unicode):
            return value
        elif isinstance(value, str):
            return unicode(value)
        else:
            return repr(value)

def create_add_word_pairs(wdict, word_pairs):
    for wp in word_pairs:
        wdict.wordpair_set.add(wp)
        wp.save()
        wdict.save()

def get_labels(user):
    all_word_pairs = WordPair.objects.filter(wdict__user=user,
                                             wdict__deleted=False,
                                             deleted=False)
    labels = set()
    for wp in all_word_pairs:
        labels.update(unicode(wp.labels).split())
    return labels

def import_textfile(s, wdict):
    """Adds words from a text file to a dictionary.

    Arguments:
    - s (str)
    - wdict (WDict)
    """

    i = 1
    word_pairs = []
    for line in s.splitlines():
        line = line.rstrip()
        if (line == '') or (line[0] == ' '):
            # This line is part of an explanation.
            if len(word_pairs) != 0:
                line = re.sub('^ {1,4}', '', line) # removing prefix spaces
                word_pairs[-1].explanation += line + '\n'
            elif line == '':
                pass
            else:
                msg = (_('Line %(linenumber)s should not have spaces in '
                         'the beginning: %(line)s') %
                       {'linenumber': i, 'line': line})
                raise EWException(msg)
        else:
            # This line contains a word pair.
            strength_date_regexp = '<(-?\d+) +(\d\d\d\d)-(\d\d)-(\d\d)>'
            regexp = (r'^(\{(\d+)\})? *(.*?) -- (.*?)' +
                      '( ' + strength_date_regexp * 2 + ')?' +
                      '$')
            r = re.search(regexp, line)
            if r is None:
                msg = (_('Line %(linenumber)s is incorrect: %(line)s') %
                       {'linenumber': i, 'line': line})
                raise EWException(msg)

            wp = WordPair()
            word_pairs.append(wp)

            wp.word_in_lang1 = r.group(3)
            wp.word_in_lang2 = r.group(4)
            wp.explanation = ''
            if r.group(5) is not None:
                wp.date_added = datetime.date.today()
                wp.date1 = datetime.date(int(r.group(7)),
                                         int(r.group(8)),
                                         int(r.group(9)))
                wp.date2 = datetime.date(int(r.group(11)),
                                         int(r.group(12)),
                                         int(r.group(13)))
                wp.strength1 = int(r.group(6))
                wp.strength2 = int(r.group(10))
            else:
                wp.date_added = datetime.date.today()
                wp.date1 = datetime.date.today()
                wp.date2 = datetime.date.today()
                wp.strength1 = 0
                wp.strength2 = 0

        i += 1

    create_add_word_pairs(wdict, word_pairs)
    return word_pairs

def import_tsv(s, wdict):
    """Adds words from a text of tab-separeted values to a dictionary.

    Arguments:
    - s (str)
    - wdict (WDict)
    """

    i = 1
    word_pairs = []
    for line in s.splitlines():
        line = line.strip()
        if (line == ''):
            continue

        fields = line.split('\t')
        if len(fields) < 2:
            msg = (_('Not enough fields in line %(linenumber)s: %(line)s') %
                   {'linenumber': i, 'line': line})
            raise EWException(msg)
        elif 2 <= len(fields) <= 3:
            wp = WordPair()
            wp.word_in_lang1 = fields[0]
            wp.word_in_lang2 = fields[1]
            if len(fields) == 3:
                wp.explanation = fields[2]
            wp.date1 = datetime.date.today()
            wp.date2 = datetime.date.today()
            wp.date_added = datetime.date.today()
            word_pairs.append(wp)
        else:
            msg = (_('Too many fields in line %(linenumber)s: %(line)s') %
                   {'linenumber': i, 'line': line})
            raise EWException(msg)

        i += 1

    create_add_word_pairs(wdict, word_pairs)
    return word_pairs

def export_textfile(wdict):
    """Prints a dictionary in the old text format.

    Arguments:
    - wdict (WDict)

    Returns: str
    """

    result = []
    for wp in wdict.wordpair_set.filter(deleted=False):
        result.append(
            '%s -- %s <%s %s><%s %s>\n' %
            (wp.word_in_lang1,
             wp.word_in_lang2,
             str(wp.strength1),
             str(wp.date1),
             str(wp.strength2),
             str(wp.date2)))
        for expl_line in wp.explanation.splitlines():
            if expl_line != '':
                result.append('    ')
                result.append(expl_line)
            result.append('\n')
    return ''.join(result)

class EWLogEntry(models.Model):

    datetime = models.DateTimeField()
    action = models.TextField()
    user = models.ForeignKey(User, blank=True, null=True)
    username = models.TextField(blank=True)
    text = models.TextField(blank=True)
    ipaddress = models.TextField(blank=True)

def log(request, action, text=''):

    logentry = EWLogEntry()
    logentry.datetime = datetime.datetime.now()
    try:
        logentry.action = action
        logentry.ipaddress = (request.META.get('REMOTE_ADDR' , '') + ', ' +
                              request.META.get('HTTP_X_FORWARDED_FOR', ''))
        if request.user.is_authenticated():
            logentry.user = request.user
            logentry.username = request.user.username

        logentry.text = text
    except Exception, e:
        logentry.action = 'Logging failed'
    logentry.save()

def parse_date(s):
    return datetime.datetime.strptime(s, '%Y-%m-%d')

##### show future #####

def incr_wcd(wcd, wdict, strength, date, count):
    strength_to_word_count = wcd.setdefault((wdict, date), {})
    try:
        strength_to_word_count[strength] += count
    except KeyError:
        strength_to_word_count[strength] = count

def get_initial_word_counts_dict(user, start_date):
    """
    Returns: wdicts, {(wdict, date): {strength: word_count}}
    """

    def add_wp(wcd, wdict, strength, date):
        if (start_date is not None) and (date < start_date):
            date = start_date
        incr_wcd(wcd, wdict, strength, date, 1)

    wcd = {}
    wdicts = WDict.objects.filter(user=user, deleted=False)
    word_pairs = WordPair.objects.filter(wdict__user=user,
                                         wdict__deleted=False,
                                         deleted=False)
    for wp in word_pairs:
        add_wp(wcd, wp.wdict, wp.strength1, wp.date1)
        add_wp(wcd, wp.wdict, wp.strength2, wp.date2)
    return wdicts, wcd

def calc_future(user, days_count, start_date):
    """
    Returns: [date], [WDict], {(WDict, date): question_count}
    """

    dates = [start_date + datetime.timedelta(i)
             for i in range(days_count)]

    wdicts, wcd = get_initial_word_counts_dict(user, start_date)

    date_to_question_count = {} # {(wdict, date): question_count}
    for date in dates:
        for wdict in wdicts:
            strength_to_word_count = wcd.pop((wdict, date), {})
            question_count = 0
            for strength, word_count in strength_to_word_count.items():
                question_count += word_count
                new_date = WordPair.next_date(strength, date)
                incr_wcd(wcd, wdict, strength + 1, new_date, word_count)
            date_to_question_count[(wdict, date)] = question_count

    return dates, wdicts, date_to_question_count
<|endoftext|>


<commit_before>from django.db import models
from django.forms import ModelForm

class FlashCard(models.Model):
    """
    A basic Flashcard.

    Has a front and a back view.
    """
    front = models.CharField(
                    max_length = 200,
                    verbose_name = "Front")
    back = models.CharField(
                    max_length = 200,
                    verbose_name = "Back")

    @models.permalink
    def get_absolute_url(self):
        return ('show_details', [str(self.id)])

    @models.permalink
    def edit(self):
        return ('edit_flashcard', [str(self.id)])

    @models.permalink
    def delete(self):
        return ('delete_flashcard', [str(self.id)])

    def __unicode__(self):
        return u"%s - %s" % (self.front, self.back)

class FlashCardForm(ModelForm):
    class Meta:
        model = FlashCard
<commit_msg>add easy_factor to model FlashCard<commit_after>from django.db import models
from django.forms import ModelForm

class FlashCard(models.Model):
    """
    A basic Flashcard.

    Has a front and a back view.
    """
    front = models.CharField(
                    max_length = 200,
                    verbose_name = "Front")
    back = models.CharField(
                    max_length = 200,
                    verbose_name = "Back")

    easy_factor = models.FloatField(default = 2.5)

    @models.permalink
    def get_absolute_url(self):
        return ('show_details', [str(self.id)])

    @models.permalink
    def edit(self):
        return ('edit_flashcard', [str(self.id)])

    @models.permalink
    def delete(self):
        return ('delete_flashcard', [str(self.id)])

    def __unicode__(self):
        return u"%s - %s" % (self.front, self.back)

    class Meta:
        verbose_name = "Flashcard"
        verbose_name_plural = "Flashcards"

class FlashCardForm(ModelForm):
    class Meta:
        model = FlashCard
        exclude = ('easy_factor', )

<|endoftext|>


<commit_before>from typing import Dict, Callable, Any

from hgicommon.models import Model
from hgicommon.serialization.serializers import PrimitiveDeserializer, PrimitiveSerializer

class PropertyMapping(Model):
    """
    Model of a mapping between a json property and a property of an object.
    """
    def __init__(
            self,
            serialized_property_name=None, object_property_name: str=None, object_constructor_parameter_name: str=None,
            serialized_property_getter: Callable[[Dict], Any]=None, serialized_property_setter: Callable[[Any, Any], None]=None,
            object_property_getter: Callable[[Any], Any]=None, object_property_setter: Callable[[Any, Any], None]=None,
            serializer_cls: type=PrimitiveSerializer, deserializer_cls: type=PrimitiveDeserializer):
        """
        Constructor.
        :param serialized_property_name:
        :param object_property_name:
        :param object_constructor_parameter_name:
        :param serialized_property_getter:
        :param serialized_property_setter:
        :param object_property_getter:
        :param object_property_setter:
        :param serializer_cls:
        :param deserializer_cls:
        """
        if serialized_property_name is not None:
            if serialized_property_getter is not None and serialized_property_setter is not None:
                raise ValueError("Redundant `serialized_property_name` argument given. It has been specified that a"
                                 "serialized property is to be used via the given property name and both a setter and"
                                 "getter of this property has been provided. To avoid confusion, the serialized "
                                 "property cannot be specified in this case.")

            if serialized_property_getter is None:
                def serialized_property_getter(obj_as_json: dict):
                    return obj_as_json[serialized_property_name]

            if serialized_property_setter is None:
                def serialized_property_setter(obj_as_json: dict, value: Any):
                    obj_as_json[serialized_property_name] = value

        if object_property_name is not None:
            # It is not possible to know what the serialized container is therefore default values cannot be set if a
            # required getter/setter is not given. Defaults can however be set in subclasses.

            if object_property_getter is not None and object_property_setter is not None:
                raise ValueError("Redundant `object_property_name` argument given. It has been specified that an"
                                 "object property is to be used via the given property name and both a setter and"
                                 "getter of this property has been provided. To avoid confusion, the object "
                                 "property cannot be specified in this case.")

            if object_property_getter is None:
                def object_property_getter(obj: Any) -> Any:
                    return obj.__getattribute__(object_property_name)

            if object_property_setter is None:
                def object_property_setter(obj: Any, value: Any):
                    obj.__setattr__(object_property_name, value)

        if object_constructor_parameter_name is not None:
            if serialized_property_getter is None:
                raise ValueError("`serialized_property_getter` or `serialized_property_name` must be defined alongside "
                                 "`object_constructor_parameter_name`")

            if object_property_setter is not None and object_constructor_parameter_name is None:
                raise ValueError("`object_property_setter` cannot be defined if `object_constructor_parameter_name` is "
                                 "given as the serialized data will be injected into the object as an argument. If an "
                                 "object property should also be set using a setter, define another mapping.")

        self.serialized_property_getter = serialized_property_getter
        self.serialized_property_setter = serialized_property_setter
        self.object_property_getter = object_property_getter
        self.object_property_setter = object_property_setter
        self.object_constructor_parameter_name = object_constructor_parameter_name
        self.serializer_cls = serializer_cls
        self.deserializer_cls = deserializer_cls
<commit_msg>Compeleted testing of serialization related code.<commit_after>from typing import Dict, Callable, Any

from hgicommon.models import Model
from hgicommon.serialization.serializers import PrimitiveDeserializer, PrimitiveSerializer

class PropertyMapping(Model):
    """
    Model of a mapping between a json property and a property of an object.
    """
    def __init__(
            self,
            serialized_property_name=None, object_property_name: str=None, object_constructor_parameter_name: str=None,
            serialized_property_getter: Callable[[Dict], Any]=None, serialized_property_setter: Callable[[Any, Any], None]=None,
            object_property_getter: Callable[[Any], Any]=None, object_property_setter: Callable[[Any, Any], None]=None,
            serializer_cls: type=PrimitiveSerializer, deserializer_cls: type=PrimitiveDeserializer):
        """
        Constructor.
        :param serialized_property_name:
        :param object_property_name:
        :param object_constructor_parameter_name:
        :param serialized_property_getter:
        :param serialized_property_setter:
        :param object_property_getter:
        :param object_property_setter:
        :param serializer_cls:
        :param deserializer_cls:
        """
        if serialized_property_name is not None:
            if serialized_property_getter is not None and serialized_property_setter is not None:
                raise ValueError("Redundant `serialized_property_name` argument given. It has been specified that a"
                                 "serialized property is to be used via the given property name and both a setter and"
                                 "getter of this property has been provided. To avoid confusion, the serialized "
                                 "property cannot be specified in this case.")

            if serialized_property_getter is None:
                def serialized_property_getter(obj_as_json: dict):
                    return obj_as_json[serialized_property_name]

            if serialized_property_setter is None:
                def serialized_property_setter(obj_as_json: dict, value: Any):
                    obj_as_json[serialized_property_name] = value

        if object_property_name is not None:
            # It is not possible to know what the serialized container is therefore default values cannot be set if a
            # required getter/setter is not given. Defaults can however be set in subclasses.

            if object_property_getter is not None and object_property_setter is not None:
                raise ValueError("Redundant `object_property_name` argument given. It has been specified that an"
                                 "object property is to be used via the given property name and both a setter and"
                                 "getter of this property has been provided. To avoid confusion, the object "
                                 "property cannot be specified in this case.")

            if object_property_getter is None:
                def object_property_getter(obj: Any) -> Any:
                    return obj.__getattribute__(object_property_name)

            if object_property_setter is None and object_constructor_parameter_name is None:
                def object_property_setter(obj: Any, value: Any):
                    obj.__setattr__(object_property_name, value)

        if object_constructor_parameter_name is not None:
            if serialized_property_getter is None:
                raise ValueError("`serialized_property_getter` or `serialized_property_name` must be defined alongside "
                                 "`object_constructor_parameter_name`")

            if object_property_setter is not None and object_constructor_parameter_name is not None:
                raise ValueError("`object_property_setter` cannot be defined if `object_constructor_parameter_name` is "
                                 "given as the serialized data will be injected into the object as an argument. If an "
                                 "object property should also be set using a setter, define another mapping.")

        self.serialized_property_getter = serialized_property_getter
        self.serialized_property_setter = serialized_property_setter
        self.object_property_getter = object_property_getter
        self.object_property_setter = object_property_setter
        self.object_constructor_parameter_name = object_constructor_parameter_name
        self.serializer_cls = serializer_cls
        self.deserializer_cls = deserializer_cls
<|endoftext|>


<commit_before>from django.db import models, connection
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User

class VoteManager(models.Manager):
    def get_score(self, obj):
        """
        Get the total score for ``obj`` and the number of votes it's received.
        """
        query = """
SELECT SUM(vote), COUNT(*) FROM %s
WHERE content_type_id = %%s
  AND object_id = %%s""" % self.model._meta.db_table
        ctype = ContentType.objects.get_for_model(obj)
        cursor = connection.cursor()
        cursor.execute(query, [ctype.id, obj.id])
        result = cursor.fetchall()[0]
        return {'score': result[0] or 0, 'num_votes': result[1]}

    def record_vote(self, obj, user, vote):
        """
        Record a user's vote on a given object. Only allows a given user
        to vote once, though that vote may be changed.

        A zero vote indicates that any existing vote should be removed.
        """
        if vote not in (+1, 0, -1):
            raise ValueError('Invalid vote (must be +1/0/-1)')
        ctype = ContentType.objects.get_for_model(obj)
        try:
            v = self.get(user=user, content_type=ctype, object_id=obj.id)
            if vote == 0:
                v.delete()
            else:
                v.vote = vote
                v.save()
        except Vote.DoesNotExist:
            if vote != 0:
                self.create(user=user, content_type=ctype,
                            object_id=obj.id, vote=vote)

    def get_top(self, Model, limit=10, reversed=False):
        """
        Get the top N scored objects for a given model.

        Yields (object, score) tuples.
        """
        ctype = ContentType.objects.get_for_model(Model)
        query = """
SELECT object_id, SUM(vote) AS score FROM %s
WHERE content_type_id = %%s
GROUP BY object_id""" % self.model._meta.db_table
        if reversed:
            query += 'HAVING SUM(vote) < 0 ORDER BY SUM(vote) ASC LIMIT %s'
        else:
            query += 'HAVING SUM(vote) > 0 ORDER BY SUM(vote) DESC LIMIT %s'
        cursor = connection.cursor()
        cursor.execute(query, [ctype.id, limit])
        results = cursor.fetchall()

        # Use in_bulk() to avoid O(limit) db hits.
        objects = Model.objects.in_bulk([id for id, score in results])

        # Yield each object, score pair. Because of the lazy nature of generic
        # relations, missing objects are silently ignored.
        for id, score in results:
            if id in objects:
                yield objects[id], score

    def get_bottom(self, Model, limit=10):
        """
        Get the bottom (i.e. most negative) N scored objects for a given model.

        Yields (object, score) tuples.
        """
        return self.get_top(Model, limit, True)

    def get_for_user(self, obj, user):
        """
        Get the vote made on the given object by the given user, or
        ``None`` if no matching vote exists.
        """
        ctype = ContentType.objects.get_for_model(obj)
        try:
            vote = self.get(content_type=ctype, object_id=obj.id, user=user)
        except Vote.DoesNotExist:
            vote = None
        return vote

SCORES = (
    ('+1', +1),
    ('-1', -1),
)

class Vote(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = models.GenericForeignKey('content_type', 'object_id')
    vote = models.SmallIntegerField(choices=SCORES)

    objects = VoteManager()

    class Meta:
        db_table = 'votes'
        # Enforce one vote per user per object
        unique_together = (('user', 'content_type', 'object_id'),)

    class Admin:
        pass

    def __str__(self):
        return '%s: %s on %s' % (self.user, self.vote, self.object)

    def is_upvote(self):
        return self.vote == 1

    def is_downvote(self):
        return self.vote == -1<commit_msg>Added verbose_name properties to Vote's Meta class<commit_after>from django.db import models, connection
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User

class VoteManager(models.Manager):
    def get_score(self, obj):
        """
        Get the total score for ``obj`` and the number of votes it's received.
        """
        query = """
SELECT SUM(vote), COUNT(*) FROM %s
WHERE content_type_id = %%s
  AND object_id = %%s""" % self.model._meta.db_table
        ctype = ContentType.objects.get_for_model(obj)
        cursor = connection.cursor()
        cursor.execute(query, [ctype.id, obj.id])
        result = cursor.fetchall()[0]
        return {'score': result[0] or 0, 'num_votes': result[1]}

    def record_vote(self, obj, user, vote):
        """
        Record a user's vote on a given object. Only allows a given user
        to vote once, though that vote may be changed.

        A zero vote indicates that any existing vote should be removed.
        """
        if vote not in (+1, 0, -1):
            raise ValueError('Invalid vote (must be +1/0/-1)')
        ctype = ContentType.objects.get_for_model(obj)
        try:
            v = self.get(user=user, content_type=ctype, object_id=obj.id)
            if vote == 0:
                v.delete()
            else:
                v.vote = vote
                v.save()
        except Vote.DoesNotExist:
            if vote != 0:
                self.create(user=user, content_type=ctype,
                            object_id=obj.id, vote=vote)

    def get_top(self, Model, limit=10, reversed=False):
        """
        Get the top N scored objects for a given model.

        Yields (object, score) tuples.
        """
        ctype = ContentType.objects.get_for_model(Model)
        query = """
SELECT object_id, SUM(vote) AS score FROM %s
WHERE content_type_id = %%s
GROUP BY object_id""" % self.model._meta.db_table
        if reversed:
            query += 'HAVING SUM(vote) < 0 ORDER BY SUM(vote) ASC LIMIT %s'
        else:
            query += 'HAVING SUM(vote) > 0 ORDER BY SUM(vote) DESC LIMIT %s'
        cursor = connection.cursor()
        cursor.execute(query, [ctype.id, limit])
        results = cursor.fetchall()

        # Use in_bulk() to avoid O(limit) db hits.
        objects = Model.objects.in_bulk([id for id, score in results])

        # Yield each object, score pair. Because of the lazy nature of generic
        # relations, missing objects are silently ignored.
        for id, score in results:
            if id in objects:
                yield objects[id], score

    def get_bottom(self, Model, limit=10):
        """
        Get the bottom (i.e. most negative) N scored objects for a given model.

        Yields (object, score) tuples.
        """
        return self.get_top(Model, limit, True)

    def get_for_user(self, obj, user):
        """
        Get the vote made on the given object by the given user, or
        ``None`` if no matching vote exists.
        """
        ctype = ContentType.objects.get_for_model(obj)
        try:
            vote = self.get(content_type=ctype, object_id=obj.id, user=user)
        except Vote.DoesNotExist:
            vote = None
        return vote

SCORES = (
    ('+1', +1),
    ('-1', -1),
)

class Vote(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = models.GenericForeignKey('content_type', 'object_id')
    vote = models.SmallIntegerField(choices=SCORES)

    objects = VoteManager()

    class Meta:
        db_table = 'votes'
        verbose_name = 'Vote'
        verbose_name_plural = 'Votes'
        # Enforce one vote per user per object
        unique_together = (('user', 'content_type', 'object_id'),)

    class Admin:
        pass

    def __str__(self):
        return '%s: %s on %s' % (self.user, self.vote, self.object)

    def is_upvote(self):
        return self.vote == 1

    def is_downvote(self):
        return self.vote == -1<|endoftext|>


<commit_before>import ghmm
import simplejson
import os.path

UP = 0
DOWN = 1
LEFT = 2
RIGHT = 3
UP_RIGHT = 4
UP_LEFT = 5
DOWN_RIGHT = 6
DOWN_LEFT = 7
GESTES_COUNT = 8
OBSERVATIONS_COUNT = 8

gestures = [
    ([UP, RIGHT], ['/usr/bin/xdotool', 'getactivewindow', 'windowkill']),
    ([UP, LEFT], ['notify-send', '"received command"', '"Hooray!"']),
    ([DOWN], ['amixer', 'set', 'Master', '10%-']),
    ([UP], ['amixer', 'set', 'Master', '10%+']),
    ([UP, DOWN, UP], ['mplayer']),
]

training_data = [[] for gesture in gestures]

# TODO: Zuordnung von Indizes stimmt noch nicht
def transition_matrix(gesture):
    gestes = list(set(gesture))
    A = [[0.1 for i in range(GESTES_COUNT)] for j in range(GESTES_COUNT)]
    # self transitions are high
    for geste in gestes:
        A[geste][geste] = 0.7

    first = gestes[0]

    for second in gestes[1:]:
        # if we have a transition, prob must be high
        A[first][second] = 0.3

    # ending element has no transitions anymore, so give it one
    A[gestes[-1]][gestes[-1]] = 1

    return A

def emission_matrix():
    B = [[float(1)/OBSERVATIONS_COUNT for i in range(OBSERVATIONS_COUNT)] for j in range(GESTES_COUNT)]

    B[UP] = [0.37, 0.04, 0.08, 0.08, 0.165, 0.165, 0.05, 0.05]
    B[DOWN] = [0.04, 0.37, 0.08, 0.08, 0.05, 0.05, 0.165, 0.165]
    B[LEFT] = [0.08, 0.08, 0.37, 0.04, 0.05, 0.165, 0.05, 0.165]
    B[RIGHT] = [0.08, 0.08, 0.04, 0.37, 0.165, 0.05, 0.165, 0.05]
    return B

def initial_vector(gesture):
    vec = [0 for i in range(GESTES_COUNT)]
    vec[gesture[0]] = 1
    return vec

# Construct parameters
models = []

sigma = ghmm.IntegerRange(0, 8)
i = 0
for gesture in gestures:
    A = transition_matrix(gesture[0])
    B = emission_matrix(gesture[0])
    pi = initial_vector(gesture[0])

    m = ghmm.HMMFromMatrices(sigma, ghmm.DiscreteDistribution(sigma), A, B, pi)
    print(m)
    if os.path.isfile(''.join(('models/', str(i), '.train'))):
        with open(''.join(('models/', str(i), '.train'))) as f:
            training_data[i] = simplejson.load(f)
            m.baumWelch(ghmm.SequenceSet(sigma, training_data[i]))
    print(m)
    models.append((m, gesture[1]))

    i += 1
<commit_msg>keep gesture order for transition matrix generation<commit_after>import ghmm
import simplejson
import os.path

UP = 0
DOWN = 1
LEFT = 2
RIGHT = 3
UP_RIGHT = 4
UP_LEFT = 5
DOWN_RIGHT = 6
DOWN_LEFT = 7
GESTES_COUNT = 8
OBSERVATIONS_COUNT = 8

gestures = [
    ([UP, RIGHT], ['/usr/bin/xdotool', 'getactivewindow', 'windowkill']),
    ([UP, LEFT], ['notify-send', '"received command"', '"Hooray!"']),
    ([DOWN], ['amixer', 'set', 'Master', '10%-']),
    ([UP], ['amixer', 'set', 'Master', '10%+']),
    ([UP, DOWN, UP], ['mplayer']),
]

training_data = [[] for gesture in gestures]

def uniq_list(seq):
    seen = set()
    return [x for x in seq if x not in seen and not seen.add(x)]

# TODO: Zuordnung von Indizes stimmt noch nicht
def transition_matrix(gesture):
    gestes = uniq_list(gesture)
    A = [[0.1 for i in range(GESTES_COUNT)] for j in range(GESTES_COUNT)]
    # self transitions are high
    for geste in gestes:
        A[geste][geste] = 0.7

    first = gestes[0]

    for second in gestes[1:]:
        # if we have a transition, prob must be high
        A[first][second] = 0.3

    # ending element has no transitions anymore, so give it one
    A[gestes[-1]][gestes[-1]] = 1

    return A

def emission_matrix():
    B = [[float(1)/OBSERVATIONS_COUNT for i in range(OBSERVATIONS_COUNT)] for j in range(GESTES_COUNT)]

    B[UP] = [0.37, 0.04, 0.08, 0.08, 0.165, 0.165, 0.05, 0.05]
    B[DOWN] = [0.04, 0.37, 0.08, 0.08, 0.05, 0.05, 0.165, 0.165]
    B[LEFT] = [0.08, 0.08, 0.37, 0.04, 0.05, 0.165, 0.05, 0.165]
    B[RIGHT] = [0.08, 0.08, 0.04, 0.37, 0.165, 0.05, 0.165, 0.05]
    return B

def initial_vector(gesture):
    vec = [0 for i in range(GESTES_COUNT)]
    vec[gesture[0]] = 1
    return vec

# Construct parameters
models = []

sigma = ghmm.IntegerRange(0, 8)
i = 0
for gesture in gestures:
    A = transition_matrix(gesture[0])
    B = emission_matrix(gesture[0])
    pi = initial_vector(gesture[0])

    m = ghmm.HMMFromMatrices(sigma, ghmm.DiscreteDistribution(sigma), A, B, pi)
    print(m)
    if os.path.isfile(''.join(('models/', str(i), '.train'))):
        with open(''.join(('models/', str(i), '.train'))) as f:
            training_data[i] = simplejson.load(f)
            m.baumWelch(ghmm.SequenceSet(sigma, training_data[i]))
    print(m)
    models.append((m, gesture[1]))

    i += 1
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import datetime

import mongoengine
from pyechonest import config as echonest_config
from pyechonest import song as echonest_song
from pyechonest import artist as echonest_artist
import requests

import config

echonest_config.ECHO_NEST_API_KEY = config.echo_nest_api_key
SPOTIFY_API = 'https://api.spotify.com/v1'

class Track(mongoengine.Document):
    id = mongoengine.StringField(primary_key=True)
    name = mongoengine.StringField(required=True)
    artist_id = mongoengine.StringField(required=True)
    artist_name = mongoengine.StringField(required=True)
    album = mongoengine.StringField(required=True)
    uri = mongoengine.StringField(required=True)
    preview_url = mongoengine.StringField(required=True)
    image = mongoengine.StringField(required=True)
    genres = mongoengine.ListField(mongoengine.StringField())
    audio_summary = mongoengine.DictField()

    @staticmethod
    def get_from_spotify(artist, title):
        # Getting data from spotify
        request_url = '{}/search'.format(SPOTIFY_API)
        query = '{} {}'.format(artist, title)
        response = requests.get(request_url, params={'q': query, 'type': 'track'}).json()

        items = response['tracks']['items']
        if not items:
            print "Couldn't find '{} - {}' on Spotify".format(artist, title)
            return None
        raw_track_data = items[0]

        track_data = dict()
        for attr in ['id', 'name', 'uri', 'preview_url']:
            track_data[attr] = raw_track_data[attr]
        track_data['artist_name'] = raw_track_data['artists'][0]['name']
        track_data['artist_id'] = raw_track_data['artists'][0]['id']
        track_data['album'] = raw_track_data['album']['name']
        track_data['image'] = raw_track_data['album']['images'][0]['url']

        # EchoNest enrichement
        songs = echonest_song.search(artist=artist, title=title)
        if not songs:
            print "Couldn't find '{} - {}' on EchoNest".format(artist, title)
            return None
        song = songs[0]
        track_data['audio_summary'] = song.audio_summary
        artist = echonest_artist.search(name=song.artist_name)[0]
        track_data['genres'] = [t['name'] for t in artist.terms]

        return Track(**track_data)

class Photo(mongoengine.Document):
    file = mongoengine.FileField(required=True)

class Submission(mongoengine.Document):
    date = mongoengine.DateTimeField(default=datetime.now)
    photo = mongoengine.ReferenceField(Photo)
    track = mongoengine.ReferenceField(Track)

if __name__ == '__main__':
    db = mongoengine.connect('test_db')
    track = Track.get_from_spotify('maskinen', 'krossa alla fönster')
    track.save()
    print track.__dict__<commit_msg>Initial implementation of similar artists<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import datetime

import mongoengine
from pyechonest import config as echonest_config
from pyechonest import song as echonest_song
from pyechonest import artist as echonest_artist
import requests

import config

echonest_config.ECHO_NEST_API_KEY = config.echo_nest_api_key
SPOTIFY_API = 'https://api.spotify.com/v1'

class Track(mongoengine.Document):
    id = mongoengine.StringField(primary_key=True)
    name = mongoengine.StringField(required=True)
    artist_id = mongoengine.StringField(required=True)
    artist_name = mongoengine.StringField(required=True)
    album = mongoengine.StringField(required=True)
    uri = mongoengine.StringField(required=True)
    preview_url = mongoengine.StringField(required=True)
    image = mongoengine.StringField(required=True)
    genres = mongoengine.ListField(mongoengine.StringField())
    audio_summary = mongoengine.DictField()

    @staticmethod
    def get_from_spotify(artist, title):
        # Getting data from spotify
        request_url = '{}/search'.format(SPOTIFY_API)
        query = '{} {}'.format(artist, title)
        response = requests.get(request_url, params={'q': query, 'type': 'track'}).json()

        items = response['tracks']['items']
        if not items:
            print "Couldn't find '{} - {}' on Spotify".format(artist, title)
            return None
        raw_track_data = items[0]

        track_data = dict()
        for attr in ['id', 'name', 'uri', 'preview_url']:
            track_data[attr] = raw_track_data[attr]
        track_data['artist_name'] = raw_track_data['artists'][0]['name']
        track_data['artist_id'] = raw_track_data['artists'][0]['id']
        track_data['album'] = raw_track_data['album']['name']
        track_data['image'] = raw_track_data['album']['images'][0]['url']

        # EchoNest enrichement
        songs = echonest_song.search(artist=artist, title=title)
        if not songs:
            print "Couldn't find '{} - {}' on EchoNest".format(artist, title)
            return None
        song = songs[0]
        track_data['audio_summary'] = song.audio_summary
        artist = echonest_artist.search(name=song.artist_name)[0]
        track_data['genres'] = [t['name'] for t in artist.terms]

        return Track(**track_data)

    def get_similar_tracks(self):
        similar_tracks = []
        for track in Track.objects():
            if any(genre in self.genres for genre in track.genres):
                similar_tracks.append(track)
        return similar_tracks

class Photo(mongoengine.Document):
    file = mongoengine.FileField(required=True)

class Submission(mongoengine.Document):
    date = mongoengine.DateTimeField(default=datetime.now)
    photo = mongoengine.ReferenceField(Photo)
    track = mongoengine.ReferenceField(Track)

if __name__ == '__main__':
    db = mongoengine.connect('test_db')
    track = Track.get_from_spotify('maskinen', 'krossa alla fönster')
    track.save()
    print track.__dict__<|endoftext|>


<commit_before>from google.appengine.ext import ndb
from google.appengine.ext import db

class User(ndb.Model):
    name = ndb.StringProperty()
    email = ndb.StringProperty()
    groups = ndb.KeyProperty(kind='Group', repeated=True)

    PARENT_KEY = ndb.Key("User", "root")

    @classmethod
    def get_by_user(cls, user):
        return cls.query(ancestor=User.PARENT_KEY).filter(cls.email == user.email().lower()).get()

    @classmethod
    def get_groups(cls, google_user):
        member = cls.query(ancestor=cls.PARENT_KEY).filter(cls.email == google_user.email().lower()).get()
        groups = []
        for group in member.groups:
            groups.append(group.get())
        return groups

class Group(ndb.Model):
    admins = ndb.KeyProperty(kind='User', repeated=True)
    members = ndb.KeyProperty(kind='User', repeated=True)
    name = ndb.StringProperty()

    PARENT_KEY = ndb.Key("Group", "root")

    @classmethod
    def get_members_from_key(cls, key):
        members = []
        for member in key.get().members:
            members.append(member.get())
        return members

    @classmethod
    def insert_group(cls, user, name):
        group = Group(parent=cls.PARENT_KEY,
                      name=name,
                      admins=[user.key],
                      members=[user.key])
        key = group.put()
        user.groups.append(key)
        user.put()

    @classmethod
    def delete_group(cls, key):
        users_query = User.query(ansestor=User.PARENT_KEY)
        for u in users_query:
            i = 0
            changed = False
            for g in u.groups:
                if str(key) == str(u.groups[i]):
                    del u.groups[i]
                    changed = True
                i += 1
            if changed:
                u.put()
        key.delete()

class Chore(ndb.Model):
    name = ndb.StringProperty()
    due = ndb.DateTimeProperty()
    frequency = ndb.StringProperty()
    points = ndb.IntegerProperty()
    readyForApproval = ndb.BooleanProperty()
    group_id = ndb.KeyProperty(kind='Group')
    assigned_to = ndb.KeyProperty(kind='User')

    PARENT_KEY = ndb.Key("Chore", "root")

    @classmethod
    def get_by_group(cls, group_id):
        return cls.query(ancestor=cls.PARENT_KEY).filter(cls.group_id == group_id)

    @classmethod
    def get_upcoming_by_user(cls, user_id):
        return cls.query(ancestor=cls.PARENT_KEY).filter(cls.assigned_to == user_id, cls.readyForApproval == False).order(cls.due)

<commit_msg>fixed ancestor<commit_after>from google.appengine.ext import ndb
from google.appengine.ext import db

class User(ndb.Model):
    name = ndb.StringProperty()
    email = ndb.StringProperty()
    groups = ndb.KeyProperty(kind='Group', repeated=True)

    PARENT_KEY = ndb.Key("User", "root")

    @classmethod
    def get_by_user(cls, user):
        return cls.query(ancestor=User.PARENT_KEY).filter(cls.email == user.email().lower()).get()

    @classmethod
    def get_groups(cls, google_user):
        member = cls.query(ancestor=cls.PARENT_KEY).filter(cls.email == google_user.email().lower()).get()
        groups = []
        for group in member.groups:
            groups.append(group.get())
        return groups

class Group(ndb.Model):
    admins = ndb.KeyProperty(kind='User', repeated=True)
    members = ndb.KeyProperty(kind='User', repeated=True)
    name = ndb.StringProperty()

    PARENT_KEY = ndb.Key("Group", "root")

    @classmethod
    def get_members_from_key(cls, key):
        members = []
        for member in key.get().members:
            members.append(member.get())
        return members

    @classmethod
    def insert_group(cls, user, name):
        group = Group(parent=cls.PARENT_KEY,
                      name=name,
                      admins=[user.key],
                      members=[user.key])
        key = group.put()
        user.groups.append(key)
        user.put()

    @classmethod
    def delete_group(cls, key):
        users_query = User.query(ancestor=User.PARENT_KEY)
        for u in users_query:
            i = 0
            changed = False
            for g in u.groups:
                if str(key) == str(u.groups[i]):
                    del u.groups[i]
                    changed = True
                i += 1
            if changed:
                u.put()
        key.delete()

class Chore(ndb.Model):
    name = ndb.StringProperty()
    due = ndb.DateTimeProperty()
    frequency = ndb.StringProperty()
    points = ndb.IntegerProperty()
    readyForApproval = ndb.BooleanProperty()
    group_id = ndb.KeyProperty(kind='Group')
    assigned_to = ndb.KeyProperty(kind='User')

    PARENT_KEY = ndb.Key("Chore", "root")

    @classmethod
    def get_by_group(cls, group_id):
        return cls.query(ancestor=cls.PARENT_KEY).filter(cls.group_id == group_id)

    @classmethod
    def get_upcoming_by_user(cls, user_id):
        return cls.query(ancestor=cls.PARENT_KEY).filter(cls.assigned_to == user_id, cls.readyForApproval == False).order(cls.due)

<|endoftext|>


<commit_before>
from django.db import models
from django.contrib.auth.models import User
from django.utils.html import format_html
from django.conf import settings

    # -------------
    # Champion_model
    # -------------

class Champion(models.Model):
    """
    The model contains a Champion name, role, lane, counters, items, and abilities.
    The __str__ method is used to return the name of the Champion as string.
    """

    champion_name = models.CharField(max_length=200)
    champion_role = models.CharField(max_length=100)
    champion_lane = models.CharField(max_length=100)
    champion_counters = models.CharField(max_length=500)
    champion_items = models.CharField(max_length=1000)

    # champion Statistics
    champion_abilities = models.CharField(max_length=2000)

    """
    champion_passive = models.CharField(max_length=2000)
    champion_Q = models.CharField(max_length=2000)
    champion_W = models.CharField(max_length=2000)
    champion_E = models.CharField(max_length=2000)
    champion_R = models.CharField(max_length=2000)
    """

    def get_absolute_url(self):
        return "/champions/%s/" % self.champion_name

    def __str__ (self):
        return self.champion_name

    # ------------
    # player_model
    # ------------

class Player(models.Model):
    """
    The model contains a player name, age, position, total_wins, season_wins, season_losses, team_name, average_kda,
    average_gold_item, average_gold_total, pref_champions.

    The __str__ method is used to return the name of the player.
    The get_absolute_url method overrides the default url so that watson get the correct url as a link.
    """

    player_name = models.CharField(max_length=200)
    player_age = models.IntegerField(default=0)

    player_position = models.CharField(max_length=50)
    season_wins = models.IntegerField(default=0)
    season_losses = models.IntegerField(default=0)
    team_name = models.CharField(max_length=200)

    average_kda = models.IntegerField(default=0)
    average_gold_min = models.IntegerField(default=0)
    average_gold_total = models.IntegerField(default=0)

    pref_champions = models.CharField(max_length=1000)

    """
    def get_absolute_url(self):
        url_name = self.player_name.replace(' ', '_')
        return "/players/%s/" % url_name
    """
    def __str__ (self):
        return self.player_name

    # ------------
    # Item_model
    # ------------

class Item(models.Model):
    """
    The model contains a item_name, item_stats, recommended_for, item_cost, item_recipe.

    The __str__ method is used to return the item name.
    The get_absolute_url method overrides the default url so that watson get the correct url as a link.
    """

    item_name = models.CharField(max_length=200)
    item_stats = models.CharField(max_length=2000)
    item_description = models.CharField(max_length=2000)
    recommended_for = models.CharField(max_length=20)
    item_cost = models.IntegerField(default=0)
    item_recipe = models.CharField(max_length=2000)
    item_picture = models.CharField(max_length=2000)

    def get_absolute_url(self):
        return "/items/%d/" % self.item_name

    def __str__ (self):
        return self.item_name

#import watson

"""
This is where the models are registered. Only the text fields can be registered or else and error will
occur.
"""

#watson.register(Champion,fields=("champion_name","champion_role", "champion_lane", "champion_counters",
#                                    "champion_items", "champion_abilities"))

#watson.register(Player,fields=("player_name","player_age","player_position", "total_wins", "season_wins",
#                               "season_losses", "team_name", "average_kda", "average_gold_match",
#                               "average_gold_total", "pref_champions" ))

#watson.register(Item,fields=("item_name", "item_stats", "recommended_for", "item_cost", "item_recipe"))

# watson.register(Champion)
# watson.register(Player)
# watson.register(Item)
<commit_msg>updated models.py file for our new fields<commit_after>
from django.db import models
from django.contrib.auth.models import User
from django.utils.html import format_html
from django.conf import settings

    # -------------
    # Champion_model
    # -------------

class Champion(models.Model):
    """
    The model contains a Champion name, role, lane, counters, items, and abilities.
    The __str__ method is used to return the name of the Champion as string.
    """
    champion_id = models.IntegerField(default=0)
    champion_name = models.CharField(max_length=200)
    champion_role = models.CharField(max_length=100)
    champion_title = models.CharField(max_length=100)
    champion_lore = models.CharField(max_length=5000)
    champion_image = models.CharField(max_length=100)
    champion_passive_name = models.CharField(max_length=100)
    champion_passive_image = models.CharField(max_length=100)
    champion_passive_description = models.CharField(max_length=1000)
    champion_q_name = models.CharField(max_length=100)
    champion_q_image = models.CharField(max_length=100)
    champion_q_description = models.CharField(max_length=1000)
    champion_w_name = models.CharField(max_length=100)
    champion_w_image = models.CharField(max_length=100)
    champion_w_description = models.CharField(max_length=1000)
    champion_e_name = models.CharField(max_length=100)
    champion_e_image = models.CharField(max_length=100)
    champion_e_description = models.CharField(max_length=1000)
    champion_r_name = models.CharField(max_length=100)
    champion_r_image = models.CharField(max_length=100)
    champion_r_description = models.CharField(max_length=1000)
    champion_champion_to_item = models.CharField(max_length=1000)

    def get_absolute_url(self):
        return "/champions/%s/" % self.champion_name

    def __str__ (self):
        return self.champion_name

    # ------------
    # player_model
    # ------------

class Player(models.Model):
    """
    The model contains a player name, age, position, total_wins, season_wins, season_losses, team_name, average_kda,
    average_gold_item, average_gold_total, pref_champions.

    The __str__ method is used to return the name of the player.
    The get_absolute_url method overrides the default url so that watson get the correct url as a link.
    """
    player_id = models.IntegerField(default=0)
    player_first_name = models.CharField(max_length=100)
    player_last_name = models.CharField(max_length=100)
    player_ign = models.CharField(max_length=100)
    player_bio = models.CharField(max_length=5000)
    player_image = models.CharField(max_length=100)
    player_role = models.CharField(max_length=100)
    player_kda = models.FloatField(default=0)
    player_gpm = models.FloatField(default=0)
    player_total_gold = models.IntegerField(default=0)
    player_games_played = models.IntegerField(default=0)
    player_player_to_champion = models.CharField(max_length=1000)

    """
    def get_absolute_url(self):
        url_name = self.player_name.replace(' ', '_')
        return "/players/%s/" % url_name
    """
    def __str__ (self):
        return self.player_name

    # ------------
    # Item_model
    # ------------

class Item(models.Model):
    """
    The model contains a item_name, item_stats, recommended_for, item_cost, item_recipe.

    The __str__ method is used to return the item name.
    The get_absolute_url method overrides the default url so that watson get the correct url as a link.
    """
    item_id = models.IntegerField(default=0)
    item_name = models.CharField(max_length=200)
    item_description = models.CharField(max_length=5000)
    item_base_gold = models.IntegerField(default=0)
    item_sell_gold = models.IntegerField(default=0)
    item_total_gold = models.IntegerField(default=0)
    item_image = models.CharField(max_length=100)

    def get_absolute_url(self):
        return "/items/%d/" % self.item_name

    def __str__ (self):
        return self.item_name

#import watson

"""
This is where the models are registered. Only the text fields can be registered or else and error will
occur.
"""

#watson.register(Champion,fields=("champion_name","champion_role", "champion_lane", "champion_counters",
#                                    "champion_items", "champion_abilities"))

#watson.register(Player,fields=("player_name","player_age","player_position", "total_wins", "season_wins",
#                               "season_losses", "team_name", "average_kda", "average_gold_match",
#                               "average_gold_total", "pref_champions" ))

#watson.register(Item,fields=("item_name", "item_stats", "recommended_for", "item_cost", "item_recipe"))

# watson.register(Champion)
# watson.register(Player)
# watson.register(Item)
<|endoftext|>


<commit_before># encoding: utf-8
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User, Group
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.contrib.sites.models import Site
from philo.utils import fattr
from django.template import add_to_builtins as register_templatetags
from django.template import Template as DjangoTemplate
from django.template import TemplateDoesNotExist
from django.template import Context, RequestContext
from django.core.exceptions import ObjectDoesNotExist
from django.utils import simplejson as json
from UserDict import DictMixin
from philo.templatetags.containers import ContainerNode
from django.template.loader_tags import ExtendsNode, ConstantIncludeNode, IncludeNode
from django.template.loader import get_template
from django.http import Http404, HttpResponse, HttpResponseServerError, HttpResponseRedirect
from django.core.servers.basehttp import FileWrapper
from django.conf import settings
from philo.validators import URLRedirectValidator

def register_value_model(model):
	pass

def unregister_value_model(model):
	pass

class Attribute(models.Model):
	entity_content_type = models.ForeignKey(ContentType, verbose_name='Entity type')
	entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID')
	entity = generic.GenericForeignKey('entity_content_type', 'entity_object_id')
	key = models.CharField(max_length=255)
	json_value = models.TextField(verbose_name='Value (JSON)', help_text='This value must be valid JSON.')

	def get_value(self):
		return json.loads(self.json_value)

	def set_value(self, value):
		self.json_value = json.dumps(value)

	def delete_value(self):
		self.json_value = json.dumps(None)

	value = property(get_value, set_value, delete_value)

	def __unicode__(self):
		return u'"%s": %s' % (self.key, self.value)

class Relationship(models.Model):
	entity_content_type = models.ForeignKey(ContentType, related_name='relationship_entity_set', verbose_name='Entity type')
	entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID')
	entity = generic.GenericForeignKey('entity_content_type', 'entity_object_id')
	key = models.CharField(max_length=255)
	value_content_type = models.ForeignKey(ContentType, related_name='relationship_value_set', verbose_name='Value type')
	value_object_id = models.PositiveIntegerField(verbose_name='Value ID')
	value = generic.GenericForeignKey('value_content_type', 'value_object_id')

	def __unicode__(self):
		return u'"%s": %s' % (self.key, self.value)

class QuerySetMapper(object, DictMixin):
	def __init__(self, queryset, passthrough=None):
		self.queryset = queryset
		self.passthrough = passthrough
	def __getitem__(self, key):
		try:
			return self.queryset.get(key__exact=key).value
		except ObjectDoesNotExist:
			if self.passthrough:
				return self.passthrough.__getitem__(key)
			raise KeyError
	def keys(self):
		keys = set(self.queryset.values_list('key', flat=True).distinct())
		if self.passthrough:
			keys += set(self.passthrough.keys())
		return list(keys)

class Entity(models.Model):
	attribute_set = generic.GenericRelation(Attribute, content_type_field='entity_content_type', object_id_field='entity_object_id')
	relationship_set = generic.GenericRelation(Relationship, content_type_field='entity_content_type', object_id_field='entity_object_id')

	@property
	def attributes(self):
		return QuerySetMapper(self.attribute_set)

	@property
	def relationships(self):
		return QuerySetMapper(self.relationship_set)

	class Meta:
		abstract = True

class Collection(models.Model):
	name = models.CharField(max_length=255)
	description = models.TextField(blank=True, null=True)

	@fattr(short_description='Members')
	def get_count(self):
		return self.members.count()

	def __unicode__(self):
		return self.name

class CollectionMemberManager(models.Manager):
	use_for_related_fields = True

	def with_model(self, model):
		return model._default_manager.filter(pk__in=self.filter(member_content_type=ContentType.objects.get_for_model(model)).values_list('member_object_id', flat=True))

class CollectionMember(models.Model):
	objects = CollectionMemberManager()
	collection = models.ForeignKey(Collection, related_name='members')
	index = models.PositiveIntegerField(verbose_name='Index', help_text='This will determine the ordering of the item within the collection. (Optional)', null=True, blank=True)
	member_content_type = models.ForeignKey(ContentType, verbose_name='Member type')
	member_object_id = models.PositiveIntegerField(verbose_name='Member ID')
	member = generic.GenericForeignKey('member_content_type', 'member_object_id')

	def __unicode__(self):
		return u'%s - %s' % (self.collection, self.member)

class TreeManager(models.Manager):
	use_for_related_fields = True

	def roots(self):
		return self.filter(parent__isnull=True)

	def get_with_path(self, path, root=None, absolute_result=True, pathsep='/'):
		"""
		Returns the object with the path, or None if there is no object with that path,
		unless absolute_result is set to False, in which case it returns a tuple containing
		the deepest object found along the path, and the remainder of the path after that
		object as a string (or None in the case that there is no remaining path).
		"""
		slugs = path.split(pathsep)
		obj = root
		remaining_slugs = list(slugs)
		remainder = None
		for slug in slugs:
			remaining_slugs.remove(slug)
			if slug: # ignore blank slugs, handles for multiple consecutive pathseps
				try:
					obj = self.get(slug__exact=slug, parent__exact=obj)
				except self.model.DoesNotExist:
					if absolute_result:
						obj = None
					remaining_slugs.insert(0, slug)
					remainder = pathsep.join(remaining_slugs)
					break
		if obj:
			if absolute_result:
				return obj
			else:
				return (obj, remainder)
		raise self.model.DoesNotExist('%s matching query does not exist.' % self.model._meta.object_name)

class TreeModel(models.Model):
	objects = TreeManager()
	parent = models.ForeignKey('self', related_name='children', null=True, blank=True)
	slug = models.SlugField()

	def get_path(self, pathsep='/', field='slug'):
		path = getattr(self, field, '?')
		parent = self.parent
		while parent:
			path = getattr(parent, field, '?') + pathsep + path
			parent = parent.parent
		return path
	path = property(get_path)

	def __unicode__(self):
		return self.path

	class Meta:
		abstract = True

class TreeEntity(TreeModel, Entity):
	@property
	def attributes(self):
		if self.parent:
			return QuerySetMapper(self.attribute_set, passthrough=self.parent.attributes)
		return super(TreeEntity, self).attributes

	@property
	def relationships(self):
		if self.parent:
			return QuerySetMapper(self.relationship_set, passthrough=self.parent.relationships)
		return super(TreeEntity, self).relationships

	class Meta:
		abstract = True

class InheritableTreeEntity(TreeEntity):
	instance_type = models.ForeignKey(ContentType, editable=False)

	def save(self, force_insert=False, force_update=False):
		if not hasattr(self, 'instance_type_ptr'):
			self.instance_type = ContentType.objects.get_for_model(self.__class__)
		super(InheritableTreeEntity, self).save(force_insert, force_update)

	@property
	def instance(self):
		try:
			return self.instance_type.get_object_for_this_type(id=self.id)
		except:
			return None

	def get_path(self, pathsep='/', field='slug'):
		path = getattr(self.instance, field, '?')
		parent = self.parent
		while parent:
			path = getattr(parent.instance, field, '?') + pathsep + path
			parent = parent.parent
		return path
	path = property(get_path)

	@property
	def attributes(self):
		if self.parent:
			return QuerySetMapper(self.instance.attribute_set, passthrough=self.parent.instance.attributes)
		return QuerySetMapper(self.instance.attribute_set)

	@property
	def relationships(self):
		if self.parent:
			return QuerySetMapper(self.instance.relationship_set, passthrough=self.parent.instance.relationships)
		return QuerySetMapper(self.instance.relationship_set)

	class Meta:
		abstract = True

class Node(InheritableTreeEntity):
	accepts_subpath = False

	def render_to_response(self, request, path=None, subpath=None):
		return HttpResponseServerError()

	class Meta:
		unique_together = (('parent', 'slug'),)

class MultiNode(Node):
	accepts_subpath = True

	urlpatterns = []

	def render_to_response(self, request, path=None, subpath=None):
		if not subpath:
			subpath = ""
		subpath = "/" + subpath
		from django.core.urlresolvers import resolve
		view, args, kwargs = resolve(subpath, urlconf=self)
		return view(request, *args, **kwargs)

	class Meta:
		abstract = True

class Redirect(Node):
	STATUS_CODES = (
		(302, 'Temporary'),
		(301, 'Permanent'),
	)
	target = models.CharField(max_length=200,validators=[URLRedirectValidator()])
	status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')

	def render_to_response(self, request, path=None, subpath=None):
		response = HttpResponseRedirect(self.target)
		response.status_code = self.status_code
		return response

class File(Node):
	""" For storing arbitrary files """
	mimetype = models.CharField(max_length=255)
	file = models.FileField(upload_to='philo/files/%Y/%m/%d')

	def render_to_response(self, request, path=None, subpath=None):
		wrapper = FileWrapper(self.file)
		response = HttpResponse(wrapper, content_type=self.mimetype)
		response['Content-Length'] = self.file.size
		return response

	def __unicode__(self):
		return self.file

class Template(TreeModel):
	name = models.CharField(max_length=255)
	documentation = models.TextField(null=True, blank=True)
	mimetype = models.CharField(max_length=255, null=True, blank=True, help_text='Default: %s' % settings.DEFAULT_CONTENT_TYPE)
	code = models.TextField(verbose_name='django template code')

	@property
	def origin(self):
		return 'philo.models.Template: ' + self.path

	@property
	def django_template(self):
		return DjangoTemplate(self.code)

	@property
	def containers(self):
		"""
		Returns a tuple where the first item is a list of names of contentlets referenced by containers,
		and the second item is a list of tuples of names and contenttypes of contentreferences referenced by containers.
		This will break if there is a recursive extends or includes in the template code.
		Due to the use of an empty Context, any extends or include tags with dynamic arguments probably won't work.
		"""
		def container_nodes(template):
			def nodelist_container_nodes(nodelist):
				nodes = []
				for node in nodelist:
					try:
						for nodelist_name in ('nodelist', 'nodelist_loop', 'nodelist_empty', 'nodelist_true', 'nodelist_false', 'nodelist_main'):
							if hasattr(node, nodelist_name):
								nodes.extend(nodelist_container_nodes(getattr(node, nodelist_name)))
						if isinstance(node, ContainerNode):
							nodes.append(node)
						elif isinstance(node, ExtendsNode):
							extended_template = node.get_parent(Context())
							if extended_template:
								nodes.extend(container_nodes(extended_template))
						elif isinstance(node, ConstantIncludeNode):
							included_template = node.template
							if included_template:
								nodes.extend(container_nodes(included_template))
						elif isinstance(node, IncludeNode):
							included_template = get_template(node.template_name.resolve(Context()))
							if included_template:
								nodes.extend(container_nodes(included_template))
					except:
						pass # fail for this node
				return nodes
			return nodelist_container_nodes(template.nodelist)
		all_nodes = container_nodes(self.django_template)
		contentlet_node_names = set([node.name for node in all_nodes if not node.references])
		contentreference_node_names = []
		contentreference_node_specs = []
		for node in all_nodes:
			if node.references and node.name not in contentreference_node_names:
				contentreference_node_specs.append((node.name, node.references))
				contentreference_node_names.append(node.name)
		return contentlet_node_names, contentreference_node_specs

	def __unicode__(self):
		return self.get_path(u' › ', 'name')

	@staticmethod
	@fattr(is_usable=True)
	def loader(template_name, template_dirs=None): # load_template_source
		try:
			template = Template.objects.get_with_path(template_name)
		except Template.DoesNotExist:
			raise TemplateDoesNotExist(template_name)
		return (template.code, template.origin)

class Page(Node):
	"""
	Represents a page - something which is rendered according to a template. The page will have a number of related Contentlets depending on the template selected - but these will appear only after the page has been saved with that template.
	"""
	template = models.ForeignKey(Template, related_name='pages')
	title = models.CharField(max_length=255)

	def render_to_response(self, request, path=None, subpath=None):
		return HttpResponse(self.template.django_template.render(RequestContext(request, {'page': self})), mimetype=self.template.mimetype)

	def __unicode__(self):
		return self.get_path(u' › ', 'title')

# the following line enables the selection of a node as the root for a given django.contrib.sites Site object
models.ForeignKey(Node, related_name='sites', null=True, blank=True).contribute_to_class(Site, 'root_node')

class Contentlet(models.Model):
	page = models.ForeignKey(Page, related_name='contentlets')
	name = models.CharField(max_length=255)
	content = models.TextField()
	dynamic = models.BooleanField(default=False)

	def __unicode__(self):
		return self.name

class ContentReference(models.Model):
	page = models.ForeignKey(Page, related_name='contentreferences')
	name = models.CharField(max_length=255)
	content_type = models.ForeignKey(ContentType, verbose_name='Content type')
	content_id = models.PositiveIntegerField(verbose_name='Content ID', blank=True, null=True)
	content = generic.GenericForeignKey('content_type', 'content_id')

	def __unicode__(self):
		return self.name

register_templatetags('philo.templatetags.containers')

register_value_model(User)
register_value_model(Group)
register_value_model(Site)
register_value_model(Collection)
register_value_model(Template)
register_value_model(Page)
<commit_msg>Added Redirect unicode.<commit_after># encoding: utf-8
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User, Group
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.contrib.sites.models import Site
from philo.utils import fattr
from django.template import add_to_builtins as register_templatetags
from django.template import Template as DjangoTemplate
from django.template import TemplateDoesNotExist
from django.template import Context, RequestContext
from django.core.exceptions import ObjectDoesNotExist
from django.utils import simplejson as json
from UserDict import DictMixin
from philo.templatetags.containers import ContainerNode
from django.template.loader_tags import ExtendsNode, ConstantIncludeNode, IncludeNode
from django.template.loader import get_template
from django.http import Http404, HttpResponse, HttpResponseServerError, HttpResponseRedirect
from django.core.servers.basehttp import FileWrapper
from django.conf import settings
from philo.validators import URLRedirectValidator

def register_value_model(model):
	pass

def unregister_value_model(model):
	pass

class Attribute(models.Model):
	entity_content_type = models.ForeignKey(ContentType, verbose_name='Entity type')
	entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID')
	entity = generic.GenericForeignKey('entity_content_type', 'entity_object_id')
	key = models.CharField(max_length=255)
	json_value = models.TextField(verbose_name='Value (JSON)', help_text='This value must be valid JSON.')

	def get_value(self):
		return json.loads(self.json_value)

	def set_value(self, value):
		self.json_value = json.dumps(value)

	def delete_value(self):
		self.json_value = json.dumps(None)

	value = property(get_value, set_value, delete_value)

	def __unicode__(self):
		return u'"%s": %s' % (self.key, self.value)

class Relationship(models.Model):
	entity_content_type = models.ForeignKey(ContentType, related_name='relationship_entity_set', verbose_name='Entity type')
	entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID')
	entity = generic.GenericForeignKey('entity_content_type', 'entity_object_id')
	key = models.CharField(max_length=255)
	value_content_type = models.ForeignKey(ContentType, related_name='relationship_value_set', verbose_name='Value type')
	value_object_id = models.PositiveIntegerField(verbose_name='Value ID')
	value = generic.GenericForeignKey('value_content_type', 'value_object_id')

	def __unicode__(self):
		return u'"%s": %s' % (self.key, self.value)

class QuerySetMapper(object, DictMixin):
	def __init__(self, queryset, passthrough=None):
		self.queryset = queryset
		self.passthrough = passthrough
	def __getitem__(self, key):
		try:
			return self.queryset.get(key__exact=key).value
		except ObjectDoesNotExist:
			if self.passthrough:
				return self.passthrough.__getitem__(key)
			raise KeyError
	def keys(self):
		keys = set(self.queryset.values_list('key', flat=True).distinct())
		if self.passthrough:
			keys += set(self.passthrough.keys())
		return list(keys)

class Entity(models.Model):
	attribute_set = generic.GenericRelation(Attribute, content_type_field='entity_content_type', object_id_field='entity_object_id')
	relationship_set = generic.GenericRelation(Relationship, content_type_field='entity_content_type', object_id_field='entity_object_id')

	@property
	def attributes(self):
		return QuerySetMapper(self.attribute_set)

	@property
	def relationships(self):
		return QuerySetMapper(self.relationship_set)

	class Meta:
		abstract = True

class Collection(models.Model):
	name = models.CharField(max_length=255)
	description = models.TextField(blank=True, null=True)

	@fattr(short_description='Members')
	def get_count(self):
		return self.members.count()

	def __unicode__(self):
		return self.name

class CollectionMemberManager(models.Manager):
	use_for_related_fields = True

	def with_model(self, model):
		return model._default_manager.filter(pk__in=self.filter(member_content_type=ContentType.objects.get_for_model(model)).values_list('member_object_id', flat=True))

class CollectionMember(models.Model):
	objects = CollectionMemberManager()
	collection = models.ForeignKey(Collection, related_name='members')
	index = models.PositiveIntegerField(verbose_name='Index', help_text='This will determine the ordering of the item within the collection. (Optional)', null=True, blank=True)
	member_content_type = models.ForeignKey(ContentType, verbose_name='Member type')
	member_object_id = models.PositiveIntegerField(verbose_name='Member ID')
	member = generic.GenericForeignKey('member_content_type', 'member_object_id')

	def __unicode__(self):
		return u'%s - %s' % (self.collection, self.member)

class TreeManager(models.Manager):
	use_for_related_fields = True

	def roots(self):
		return self.filter(parent__isnull=True)

	def get_with_path(self, path, root=None, absolute_result=True, pathsep='/'):
		"""
		Returns the object with the path, or None if there is no object with that path,
		unless absolute_result is set to False, in which case it returns a tuple containing
		the deepest object found along the path, and the remainder of the path after that
		object as a string (or None in the case that there is no remaining path).
		"""
		slugs = path.split(pathsep)
		obj = root
		remaining_slugs = list(slugs)
		remainder = None
		for slug in slugs:
			remaining_slugs.remove(slug)
			if slug: # ignore blank slugs, handles for multiple consecutive pathseps
				try:
					obj = self.get(slug__exact=slug, parent__exact=obj)
				except self.model.DoesNotExist:
					if absolute_result:
						obj = None
					remaining_slugs.insert(0, slug)
					remainder = pathsep.join(remaining_slugs)
					break
		if obj:
			if absolute_result:
				return obj
			else:
				return (obj, remainder)
		raise self.model.DoesNotExist('%s matching query does not exist.' % self.model._meta.object_name)

class TreeModel(models.Model):
	objects = TreeManager()
	parent = models.ForeignKey('self', related_name='children', null=True, blank=True)
	slug = models.SlugField()

	def get_path(self, pathsep='/', field='slug'):
		path = getattr(self, field, '?')
		parent = self.parent
		while parent:
			path = getattr(parent, field, '?') + pathsep + path
			parent = parent.parent
		return path
	path = property(get_path)

	def __unicode__(self):
		return self.path

	class Meta:
		abstract = True

class TreeEntity(TreeModel, Entity):
	@property
	def attributes(self):
		if self.parent:
			return QuerySetMapper(self.attribute_set, passthrough=self.parent.attributes)
		return super(TreeEntity, self).attributes

	@property
	def relationships(self):
		if self.parent:
			return QuerySetMapper(self.relationship_set, passthrough=self.parent.relationships)
		return super(TreeEntity, self).relationships

	class Meta:
		abstract = True

class InheritableTreeEntity(TreeEntity):
	instance_type = models.ForeignKey(ContentType, editable=False)

	def save(self, force_insert=False, force_update=False):
		if not hasattr(self, 'instance_type_ptr'):
			self.instance_type = ContentType.objects.get_for_model(self.__class__)
		super(InheritableTreeEntity, self).save(force_insert, force_update)

	@property
	def instance(self):
		try:
			return self.instance_type.get_object_for_this_type(id=self.id)
		except:
			return None

	def get_path(self, pathsep='/', field='slug'):
		path = getattr(self.instance, field, '?')
		parent = self.parent
		while parent:
			path = getattr(parent.instance, field, '?') + pathsep + path
			parent = parent.parent
		return path
	path = property(get_path)

	@property
	def attributes(self):
		if self.parent:
			return QuerySetMapper(self.instance.attribute_set, passthrough=self.parent.instance.attributes)
		return QuerySetMapper(self.instance.attribute_set)

	@property
	def relationships(self):
		if self.parent:
			return QuerySetMapper(self.instance.relationship_set, passthrough=self.parent.instance.relationships)
		return QuerySetMapper(self.instance.relationship_set)

	class Meta:
		abstract = True

class Node(InheritableTreeEntity):
	accepts_subpath = False

	def render_to_response(self, request, path=None, subpath=None):
		return HttpResponseServerError()

	class Meta:
		unique_together = (('parent', 'slug'),)

class MultiNode(Node):
	accepts_subpath = True

	urlpatterns = []

	def render_to_response(self, request, path=None, subpath=None):
		if not subpath:
			subpath = ""
		subpath = "/" + subpath
		from django.core.urlresolvers import resolve
		view, args, kwargs = resolve(subpath, urlconf=self)
		return view(request, *args, **kwargs)

	class Meta:
		abstract = True

class Redirect(Node):
	STATUS_CODES = (
		(302, 'Temporary'),
		(301, 'Permanent'),
	)
	target = models.CharField(max_length=200,validators=[URLRedirectValidator()])
	status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')

	def render_to_response(self, request, path=None, subpath=None):
		response = HttpResponseRedirect(self.target)
		response.status_code = self.status_code
		return response

	def __unicode__(self):
		return self.slug

class File(Node):
	""" For storing arbitrary files """
	mimetype = models.CharField(max_length=255)
	file = models.FileField(upload_to='philo/files/%Y/%m/%d')

	def render_to_response(self, request, path=None, subpath=None):
		wrapper = FileWrapper(self.file)
		response = HttpResponse(wrapper, content_type=self.mimetype)
		response['Content-Length'] = self.file.size
		return response

	def __unicode__(self):
		return self.file

class Template(TreeModel):
	name = models.CharField(max_length=255)
	documentation = models.TextField(null=True, blank=True)
	mimetype = models.CharField(max_length=255, null=True, blank=True, help_text='Default: %s' % settings.DEFAULT_CONTENT_TYPE)
	code = models.TextField(verbose_name='django template code')

	@property
	def origin(self):
		return 'philo.models.Template: ' + self.path

	@property
	def django_template(self):
		return DjangoTemplate(self.code)

	@property
	def containers(self):
		"""
		Returns a tuple where the first item is a list of names of contentlets referenced by containers,
		and the second item is a list of tuples of names and contenttypes of contentreferences referenced by containers.
		This will break if there is a recursive extends or includes in the template code.
		Due to the use of an empty Context, any extends or include tags with dynamic arguments probably won't work.
		"""
		def container_nodes(template):
			def nodelist_container_nodes(nodelist):
				nodes = []
				for node in nodelist:
					try:
						for nodelist_name in ('nodelist', 'nodelist_loop', 'nodelist_empty', 'nodelist_true', 'nodelist_false', 'nodelist_main'):
							if hasattr(node, nodelist_name):
								nodes.extend(nodelist_container_nodes(getattr(node, nodelist_name)))
						if isinstance(node, ContainerNode):
							nodes.append(node)
						elif isinstance(node, ExtendsNode):
							extended_template = node.get_parent(Context())
							if extended_template:
								nodes.extend(container_nodes(extended_template))
						elif isinstance(node, ConstantIncludeNode):
							included_template = node.template
							if included_template:
								nodes.extend(container_nodes(included_template))
						elif isinstance(node, IncludeNode):
							included_template = get_template(node.template_name.resolve(Context()))
							if included_template:
								nodes.extend(container_nodes(included_template))
					except:
						pass # fail for this node
				return nodes
			return nodelist_container_nodes(template.nodelist)
		all_nodes = container_nodes(self.django_template)
		contentlet_node_names = set([node.name for node in all_nodes if not node.references])
		contentreference_node_names = []
		contentreference_node_specs = []
		for node in all_nodes:
			if node.references and node.name not in contentreference_node_names:
				contentreference_node_specs.append((node.name, node.references))
				contentreference_node_names.append(node.name)
		return contentlet_node_names, contentreference_node_specs

	def __unicode__(self):
		return self.get_path(u' › ', 'name')

	@staticmethod
	@fattr(is_usable=True)
	def loader(template_name, template_dirs=None): # load_template_source
		try:
			template = Template.objects.get_with_path(template_name)
		except Template.DoesNotExist:
			raise TemplateDoesNotExist(template_name)
		return (template.code, template.origin)

class Page(Node):
	"""
	Represents a page - something which is rendered according to a template. The page will have a number of related Contentlets depending on the template selected - but these will appear only after the page has been saved with that template.
	"""
	template = models.ForeignKey(Template, related_name='pages')
	title = models.CharField(max_length=255)

	def render_to_response(self, request, path=None, subpath=None):
		return HttpResponse(self.template.django_template.render(RequestContext(request, {'page': self})), mimetype=self.template.mimetype)

	def __unicode__(self):
		return self.get_path(u' › ', 'title')

# the following line enables the selection of a node as the root for a given django.contrib.sites Site object
models.ForeignKey(Node, related_name='sites', null=True, blank=True).contribute_to_class(Site, 'root_node')

class Contentlet(models.Model):
	page = models.ForeignKey(Page, related_name='contentlets')
	name = models.CharField(max_length=255)
	content = models.TextField()
	dynamic = models.BooleanField(default=False)

	def __unicode__(self):
		return self.name

class ContentReference(models.Model):
	page = models.ForeignKey(Page, related_name='contentreferences')
	name = models.CharField(max_length=255)
	content_type = models.ForeignKey(ContentType, verbose_name='Content type')
	content_id = models.PositiveIntegerField(verbose_name='Content ID', blank=True, null=True)
	content = generic.GenericForeignKey('content_type', 'content_id')

	def __unicode__(self):
		return self.name

register_templatetags('philo.templatetags.containers')

register_value_model(User)
register_value_model(Group)
register_value_model(Site)
register_value_model(Collection)
register_value_model(Template)
register_value_model(Page)
<|endoftext|>