<commit_before>from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import localtime

import datetime
import math

class SleepManager(models.Manager):
    def totalSleep(self):
        sleeps =  Sleep.objects.all()
        return sum((sleep.end_time - sleep.start_time for sleep in sleeps),datetime.timedelta(0))

    def sleepTimes(self,res=1):
        sleeps = Sleep.objects.all()
        atTime = [0] * (24 * 60 / res)
        for sleep in sleeps:
            startDate = localtime(sleep.start_time).date()
            endDate = localtime(sleep.end_time).date()
            dr = [startDate + datetime.timedelta(i) for i in range((endDate-startDate).days + 1)]
            for d in dr:
                if d == startDate:
                    startTime = localtime(sleep.start_time).time()
                else:
                    startTime = datetime.time(0)
                if d == endDate:
                    endTime = localtime(sleep.end_time).time()
                else:
                    endTime = datetime.time(23,59)
                for i in range((startTime.hour * 60 + startTime.minute) / res, (endTime.hour * 60 + endTime.minute + 1) / res):
                    atTime[i]+=1
        return atTime

class Sleep(models.Model):
    objects = SleepManager()

    user = models.ForeignKey(User)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()
    comments = models.TextField(blank=True)
    date = models.DateField()

    def __unicode__(self):
        return "Sleep from %s to %s" % (self.start_time,self.end_time)

    def length(self):
        return self.end_time - self.start_time

    def overlaps(self, otherSleep):
        return (min(self.end_time, otherSleep.end_time) - max(self.start_time, otherSleep.start_time) < datetime.timedelta(0))

    def validate_unique(self, exclude=None):
        #Yes this is derpy and inefficient and really should actually use the exclude field
        from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
        sleepq = self.user.sleep_set.all()
        for i in sleepq:
            if self.overlaps(i): raise ValidationError(u'Error: Overlapping Sleep Detected! You can\'t be asleep twice at the same time!')

class Allnighter(models.Model):
    user = models.ForeignKey(User)
    date = models.DateField()
    comments = models.TextField(blank=True)

class SleeperProfile(models.Model):
    user = models.OneToOneField(User)
    # all other fields should have a default
    PRIVACY_HIDDEN = -100
    PRIVACY_REDACTED = -50
    PRIVACY_NORMAL = 0
    PRIVACY_STATS = 50
    PRIVACY_PUBLIC = 100
    PRIVACY_CHOICES = (
            (PRIVACY_HIDDEN, 'Hidden'),
            (PRIVACY_REDACTED, 'Redacted'),
            (PRIVACY_NORMAL, 'Normal'),
            (PRIVACY_STATS, 'Stats Public'),
            (PRIVACY_PUBLIC, 'Sleep Public'),
            )
    privacy = models.SmallIntegerField(choices=PRIVACY_CHOICES,default=PRIVACY_NORMAL,verbose_name='Privacy to anonymous users')
    privacyLoggedIn = models.SmallIntegerField(choices=PRIVACY_CHOICES,default=PRIVACY_NORMAL,verbose_name='Privacy to logged-in users')
    privacyFriends = models.SmallIntegerField(choices=PRIVACY_CHOICES,default=PRIVACY_NORMAL,verbose_name='Privacy to friends')
    friends = models.ManyToManyField(User,related_name='friends+',blank=True)
    follows = models.ManyToManyField(User,related_name='follows+',blank=True)
    use12HourTime = models.BooleanField(default=False)

    emailreminders = models.BooleanField(default=False)

    def __unicode__(self):
        return "SleeperProfile for user %s" % self.user

class SleeperManager(models.Manager):
    def sorted_sleepers(self,sortBy='zScore',user=None):
        sleepers = Sleeper.objects.all().prefetch_related('sleep_set','sleeperprofile')
        scored=[]
        extra=[]
        for sleeper in sleepers:
            if len(sleeper.sleepPerDay())>2 and sleeper.sleepPerDay(packDates=True)[-1]['date'] >= datetime.date.today()-datetime.timedelta(5):
                p = sleeper.getOrCreateProfile()
                if user is None:
                    priv = p.PRIVACY_HIDDEN
                elif user is 'all':
                    priv = p.PRIVACY_PUBLIC
                elif user.is_anonymous():
                    priv = p.privacy
                elif user.pk==sleeper.pk:
                    priv = p.PRIVACY_PUBLIC
                else:
                    priv = p.privacyLoggedIn

                if priv<=p.PRIVACY_REDACTED:
                    sleeper.displayName="[redacted]"
                else:
                    sleeper.displayName=sleeper.username
                if priv>p.PRIVACY_HIDDEN:
                    d=sleeper.decayStats()
                    d['user']=sleeper
                    if user.is_authenticated():
                        if user.pk==sleeper.pk:
                            d['opcode']='me' #I'm using opcodes to mark specific users as self or friend.
                    else:
                        d['opcode'] = None
                    scored.append(d)
            else:
                if 'is_authenticated' in dir(user) and user.is_authenticated() and user.pk == sleeper.pk:
                    d = sleeper.decayStats()
                    d['rank']='n/a'
                    sleeper.displayName=sleeper.username
                    d['user']=sleeper
                    d['opcode']='me'
                    extra.append(d)
        scored.sort(key=lambda x: -x[sortBy])
        for i in xrange(len(scored)):
            scored[i]['rank']=i+1
        return scored+extra

class Sleeper(User):
    class Meta:
        proxy = True

    objects = SleeperManager()

    def getOrCreateProfile(self):
        return SleeperProfile.objects.get_or_create(user=self)[0]

    def timeSlept(self,start=datetime.date.min,end=datetime.datetime.max):
        sleeps = self.sleep_set.filter(date__gte=start,date__lte=end)
        return sum([s.end_time-s.start_time for s in sleeps],datetime.timedelta(0))

    def sleepPerDay(self,start=datetime.date.min,end=datetime.date.max,packDates=False,hours=False):
        if start==datetime.date.min and end==datetime.date.max:
            sleeps = self.sleep_set.values('date','start_time','end_time')
        else:
            sleeps = self.sleep_set.filter(date__gte=start,date__lte=end).values('date','start_time','end_time')
        if sleeps:
            dates=map(lambda x: x['date'], sleeps)
            first = min(dates)
            last = max(dates)
            n = (last-first).days + 1
            dateRange = [first + datetime.timedelta(i) for i in range(0,n)]
            byDays = [sum([(s['end_time']-s['start_time']).total_seconds() for s in filter(lambda x: x['date']==d,sleeps)]) for d in dateRange]
            if hours:
                byDays = map(lambda x: x/3600,byDays)
            if packDates:
                return [{'date' : first + datetime.timedelta(i), 'slept' : byDays[i]} for i in range(0,n)]
            else:
                return byDays
        else:
            return []

    def wakeUpTime(self, date=datetime.date.today()):
        sleeps = self.sleep_set.filter(date=date)
        if sleeps.count() == 0: return None
        times = [(s.end_time - datetime.timedelta(hours=4)).time() for s in sleeps if s.length() >= datetime.timedelta(hours=3)]
        if len(times) == 0: return None
        else: return min(times)

    def avgWakeUpTime(self, start = datetime.date.min, end=datetime.date.max):
        import math
        sleeps = self.sleep_set.filter(date__gte=start, date__lte=end).values('date', 'start_time', 'end_time')
        if sleeps: dates=map(lambda x: x['date'], sleeps)
        else: return None
        def genDays(start, end):
            d = start
            while d <= end:
                yield d
                d += datetime.timedelta(1)
        times = [self.wakeUpTime(d) for d in genDays(min(dates), max(dates))]
        ctimes = [t.hour*3600 + t.minute*60 + t.second for t in times if t != None]
        if len(ctimes) == 0: return None
        av = sum(ctimes)/len(ctimes)
        return datetime.time(int(math.floor(av/3600)), int(math.floor((av%3600)/60)), int(math.floor((av%60))))

    def movingStats(self,start=datetime.date.min,end=datetime.date.max):
        sleep = self.sleepPerDay(start,end)
        d = {}
        try:
            avg = sum(sleep)/len(sleep)
            d['avg']=avg
            if len(sleep)>2:
                stDev = math.sqrt(sum(map(lambda x: (x-avg)**2, sleep))/(len(sleep)-1.5)) #subtracting 1.5 is correct according to wikipedia
                d['stDev']=stDev
                d['zScore']=avg-stDev
        except:
            pass
        try:
            avgSqrt = (sum(map(lambda x: math.sqrt(x),sleep))/len(sleep))**2
            d['avgSqrt']=avgSqrt
        except:
            pass
        for k in ['avg','stDev','zScore','avgSqrt']:
            if k not in d:
                d[k]=datetime.timedelta(0)
            else:
                d[k]=datetime.timedelta(0,d[k])
        return d

    def decaying(self,data,hl,stDev=False):
        s = 0
        w = 0
        for i in range(len(data)):
            s+=2**(-i/float(hl))*data[-i-1]
            w+=2**(-i/float(hl))
        if stDev:
            w = w*(len(data)-1.5)/len(data)
        return s/w

    def decayStats(self,end=datetime.date.max,hl=4):
        sleep = self.sleepPerDay(datetime.date.min,end)
        d = {}
        try:
            avg = self.decaying(sleep,hl)
            d['avg']=avg
            stDev = math.sqrt(self.decaying(map(lambda x: (x-avg)**2,sleep),hl,True))
            d['stDev']=stDev
            d['zScore']=avg-stDev
        except:
            pass
        try:
            avgSqrt = self.decaying(map(lambda x: math.sqrt(x),sleep),hl)**2
            d['avgSqrt']=avgSqrt
        except:
            pass
        for k in ['avg','stDev','zScore','avgSqrt']:
            if k not in d:
                d[k]=datetime.timedelta(0)
            else:
                d[k]=datetime.timedelta(0,d[k])
        return d

<commit_msg>Adds sleep time; minor changes to calculation of wake times.<commit_after>from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import localtime

import datetime
import math

class SleepManager(models.Manager):
    def totalSleep(self):
        sleeps =  Sleep.objects.all()
        return sum((sleep.end_time - sleep.start_time for sleep in sleeps),datetime.timedelta(0))

    def sleepTimes(self,res=1):
        sleeps = Sleep.objects.all()
        atTime = [0] * (24 * 60 / res)
        for sleep in sleeps:
            startDate = localtime(sleep.start_time).date()
            endDate = localtime(sleep.end_time).date()
            dr = [startDate + datetime.timedelta(i) for i in range((endDate-startDate).days + 1)]
            for d in dr:
                if d == startDate:
                    startTime = localtime(sleep.start_time).time()
                else:
                    startTime = datetime.time(0)
                if d == endDate:
                    endTime = localtime(sleep.end_time).time()
                else:
                    endTime = datetime.time(23,59)
                for i in range((startTime.hour * 60 + startTime.minute) / res, (endTime.hour * 60 + endTime.minute + 1) / res):
                    atTime[i]+=1
        return atTime

class Sleep(models.Model):
    objects = SleepManager()

    user = models.ForeignKey(User)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()
    comments = models.TextField(blank=True)
    date = models.DateField()

    def __unicode__(self):
        return "Sleep from %s to %s" % (self.start_time,self.end_time)

    def length(self):
        return self.end_time - self.start_time

    def overlaps(self, otherSleep):
        return (min(self.end_time, otherSleep.end_time) - max(self.start_time, otherSleep.start_time) < datetime.timedelta(0))

    def validate_unique(self, exclude=None):
        #Yes this is derpy and inefficient and really should actually use the exclude field
        from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
        sleepq = self.user.sleep_set.all()
        for i in sleepq:
            if self.overlaps(i): raise ValidationError(u'Error: Overlapping Sleep Detected! You can\'t be asleep twice at the same time!')

class Allnighter(models.Model):
    user = models.ForeignKey(User)
    date = models.DateField()
    comments = models.TextField(blank=True)

class SleeperProfile(models.Model):
    user = models.OneToOneField(User)
    # all other fields should have a default
    PRIVACY_HIDDEN = -100
    PRIVACY_REDACTED = -50
    PRIVACY_NORMAL = 0
    PRIVACY_STATS = 50
    PRIVACY_PUBLIC = 100
    PRIVACY_CHOICES = (
            (PRIVACY_HIDDEN, 'Hidden'),
            (PRIVACY_REDACTED, 'Redacted'),
            (PRIVACY_NORMAL, 'Normal'),
            (PRIVACY_STATS, 'Stats Public'),
            (PRIVACY_PUBLIC, 'Sleep Public'),
            )
    privacy = models.SmallIntegerField(choices=PRIVACY_CHOICES,default=PRIVACY_NORMAL,verbose_name='Privacy to anonymous users')
    privacyLoggedIn = models.SmallIntegerField(choices=PRIVACY_CHOICES,default=PRIVACY_NORMAL,verbose_name='Privacy to logged-in users')
    privacyFriends = models.SmallIntegerField(choices=PRIVACY_CHOICES,default=PRIVACY_NORMAL,verbose_name='Privacy to friends')
    friends = models.ManyToManyField(User,related_name='friends+',blank=True)
    follows = models.ManyToManyField(User,related_name='follows+',blank=True)
    use12HourTime = models.BooleanField(default=False)

    emailreminders = models.BooleanField(default=False)

    def __unicode__(self):
        return "SleeperProfile for user %s" % self.user

class SleeperManager(models.Manager):
    def sorted_sleepers(self,sortBy='zScore',user=None):
        sleepers = Sleeper.objects.all().prefetch_related('sleep_set','sleeperprofile')
        scored=[]
        extra=[]
        for sleeper in sleepers:
            if len(sleeper.sleepPerDay())>2 and sleeper.sleepPerDay(packDates=True)[-1]['date'] >= datetime.date.today()-datetime.timedelta(5):
                p = sleeper.getOrCreateProfile()
                if user is None:
                    priv = p.PRIVACY_HIDDEN
                elif user is 'all':
                    priv = p.PRIVACY_PUBLIC
                elif user.is_anonymous():
                    priv = p.privacy
                elif user.pk==sleeper.pk:
                    priv = p.PRIVACY_PUBLIC
                else:
                    priv = p.privacyLoggedIn

                if priv<=p.PRIVACY_REDACTED:
                    sleeper.displayName="[redacted]"
                else:
                    sleeper.displayName=sleeper.username
                if priv>p.PRIVACY_HIDDEN:
                    d=sleeper.decayStats()
                    d['user']=sleeper
                    if user.is_authenticated():
                        if user.pk==sleeper.pk:
                            d['opcode']='me' #I'm using opcodes to mark specific users as self or friend.
                    else:
                        d['opcode'] = None
                    scored.append(d)
            else:
                if 'is_authenticated' in dir(user) and user.is_authenticated() and user.pk == sleeper.pk:
                    d = sleeper.decayStats()
                    d['rank']='n/a'
                    sleeper.displayName=sleeper.username
                    d['user']=sleeper
                    d['opcode']='me'
                    extra.append(d)
        scored.sort(key=lambda x: -x[sortBy])
        for i in xrange(len(scored)):
            scored[i]['rank']=i+1
        return scored+extra

class Sleeper(User):
    class Meta:
        proxy = True

    objects = SleeperManager()

    def getOrCreateProfile(self):
        return SleeperProfile.objects.get_or_create(user=self)[0]

    def timeSlept(self,start=datetime.date.min,end=datetime.datetime.max):
        sleeps = self.sleep_set.filter(date__gte=start,date__lte=end)
        return sum([s.end_time-s.start_time for s in sleeps],datetime.timedelta(0))

    def sleepPerDay(self,start=datetime.date.min,end=datetime.date.max,packDates=False,hours=False):
        if start==datetime.date.min and end==datetime.date.max:
            sleeps = self.sleep_set.values('date','start_time','end_time')
        else:
            sleeps = self.sleep_set.filter(date__gte=start,date__lte=end).values('date','start_time','end_time')
        if sleeps:
            dates=map(lambda x: x['date'], sleeps)
            first = min(dates)
            last = max(dates)
            n = (last-first).days + 1
            dateRange = [first + datetime.timedelta(i) for i in range(0,n)]
            byDays = [sum([(s['end_time']-s['start_time']).total_seconds() for s in filter(lambda x: x['date']==d,sleeps)]) for d in dateRange]
            if hours:
                byDays = map(lambda x: x/3600,byDays)
            if packDates:
                return [{'date' : first + datetime.timedelta(i), 'slept' : byDays[i]} for i in range(0,n)]
            else:
                return byDays
        else:
            return []

    def goToSleepTime(self, date=datetime.date.today()):
        sleeps = self.sleep_set.filter(date=date)
        if sleeps.count() == 0: return None
        times = [s.start_time for s in sleeps if s.length() >= datetime.timedelta(hours=3)]
        if len(times) == 0: return None
        else: return max(times).time()

    def avgGoToSleepTime(self, start = datetime.date.min, end=datetime.date.max):
        import math
        sleeps = self.sleep_set.filter(date__gte=start, date__lte=end).values('date', 'start_time', 'end_time')
        if sleeps: dates=map(lambda x: x['date'], sleeps)
        else: return None
        def genDays(start, end):
            d = start
            while d <= end:
                yield d
                d += datetime.timedelta(1)
        times = [self.goToSleepTime(d) for d in genDays(min(dates), max(dates))]
        ctimes = [t.hour*3600 + t.minute*60 + t.second for t in times if t != None]
        if len(ctimes) == 0: return None
        av = sum(ctimes)/len(ctimes)
        return datetime.time(int(math.floor(av/3600)), int(math.floor((av%3600)/60)), int(math.floor((av%60))))

    def wakeUpTime(self, date=datetime.date.today()):
        sleeps = self.sleep_set.filter(date=date)
        if sleeps.count() == 0: return None
        times = [s.end_time for s in sleeps if s.length() >= datetime.timedelta(hours=3)]
        if len(times) == 0: return None
        else: return min(times).time()

    def avgWakeUpTime(self, start = datetime.date.min, end=datetime.date.max):
        import math
        sleeps = self.sleep_set.filter(date__gte=start, date__lte=end).values('date', 'start_time', 'end_time')
        if sleeps: dates=map(lambda x: x['date'], sleeps)
        else: return None
        def genDays(start, end):
            d = start
            while d <= end:
                yield d
                d += datetime.timedelta(1)
        times = [self.wakeUpTime(d) for d in genDays(min(dates), max(dates))]
        ctimes = [t.hour*3600 + t.minute*60 + t.second for t in times if t != None]
        if len(ctimes) == 0: return None
        av = sum(ctimes)/len(ctimes)
        return datetime.time(int(math.floor(av/3600)), int(math.floor((av%3600)/60)), int(math.floor((av%60))))

    def movingStats(self,start=datetime.date.min,end=datetime.date.max):
        sleep = self.sleepPerDay(start,end)
        d = {}
        try:
            avg = sum(sleep)/len(sleep)
            d['avg']=avg
            if len(sleep)>2:
                stDev = math.sqrt(sum(map(lambda x: (x-avg)**2, sleep))/(len(sleep)-1.5)) #subtracting 1.5 is correct according to wikipedia
                d['stDev']=stDev
                d['zScore']=avg-stDev
        except:
            pass
        try:
            avgSqrt = (sum(map(lambda x: math.sqrt(x),sleep))/len(sleep))**2
            d['avgSqrt']=avgSqrt
        except:
            pass
        for k in ['avg','stDev','zScore','avgSqrt']:
            if k not in d:
                d[k]=datetime.timedelta(0)
            else:
                d[k]=datetime.timedelta(0,d[k])
        return d

    def decaying(self,data,hl,stDev=False):
        s = 0
        w = 0
        for i in range(len(data)):
            s+=2**(-i/float(hl))*data[-i-1]
            w+=2**(-i/float(hl))
        if stDev:
            w = w*(len(data)-1.5)/len(data)
        return s/w

    def decayStats(self,end=datetime.date.max,hl=4):
        sleep = self.sleepPerDay(datetime.date.min,end)
        d = {}
        try:
            avg = self.decaying(sleep,hl)
            d['avg']=avg
            stDev = math.sqrt(self.decaying(map(lambda x: (x-avg)**2,sleep),hl,True))
            d['stDev']=stDev
            d['zScore']=avg-stDev
        except:
            pass
        try:
            avgSqrt = self.decaying(map(lambda x: math.sqrt(x),sleep),hl)**2
            d['avgSqrt']=avgSqrt
        except:
            pass
        for k in ['avg','stDev','zScore','avgSqrt']:
            if k not in d:
                d[k]=datetime.timedelta(0)
            else:
                d[k]=datetime.timedelta(0,d[k])
        return d

<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Views for creating/editing GCI Tasks.
"""

import datetime

from google.appengine.ext import db

from django import forms as django_forms
from django.utils.translation import ugettext

from soc.logic import cleaning
from soc.views import forms
from soc.views.helper import access_checker
from soc.views.helper import url_patterns
from soc.views.template import Template

from soc.modules.gci.logic import profile as profile_logic
from soc.modules.gci.models import task
from soc.modules.gci.models.task import DIFFICULTIES
from soc.modules.gci.models.organization import GCIOrganization
from soc.modules.gci.models.profile import GCIProfile
from soc.modules.gci.views import forms as gci_forms
from soc.modules.gci.views.base import RequestHandler
from soc.modules.gci.views.helper.url_patterns import url

def mentorChoicesForOrg(task, org):
  """Builds the tuple of mentor choice 2-tuples for the Django choice field.

  Args:
    task: GCITask entity for which the create page is being created
    org: The organization entity for which the mentor choices should be
         constructed.
  """
  mentors = profile_logic.queryAllMentorsForOrg(org)
  return ((str(m.key()), m.name()) for m in mentors)

class TaskEditPostClaimForm(gci_forms.GCIModelForm):
  """Django form for the task editing after the task is published page.
  """

  tags = django_forms.CharField(
      label=ugettext('Tags'),
      help_text=ugettext('Describe this task with tags (comma separated). '
                         'Ex: Linux, Apache, C++, GUI'))

  def __init__(self, data, *args, **kwargs):
    super(TaskEditPostClaimForm, self).__init__(*args, **kwargs)

    self.request_data = data
    self.organization = self.request_data.organization if not self.instance \
        else self.instance.org

    self.POST = args[0] if len(args) > 0 and args[0] else None

    mentor_choices = list(mentorChoicesForOrg(self.instance, self.organization))

    self.fields['mentors'] = django_forms.MultipleChoiceField(
        label=ugettext('Mentors'), required=False,
        widget=gci_forms.MultipleSelectWidget(
        attrs={
            'select_id': 'assign-mentor',
            'wrapper_id': 'select-mentors-wrapper',
            'add_new_text': 'add another mentor',
            }, disabled_option=('', 'Select a mentor')),
        choices=mentor_choices)

    if self.instance:
      self.fields['tags'].initial = self.instance.tags_string(
          self.instance.arbit_tag)

    # Bind all the fields here to boundclass since we do not iterate
    # over the fields using iterator for this form.
    self.bound_fields = {}
    for name, field in self.fields.items():
      self.bound_fields[name] = gci_forms.GCIBoundField(self, field, name)

  def _getInitialValuesForList(self, field):
    """Returns the initial values for the field which take list of values.

    One of the following 3 cases can happen:
    1. If POST attribute exists and there are are no values for the given
       field empty list is returned.
    2. It checks if the POST data contains some value(s) for the given field,
       if so the method returns that as the intial value.
    3. If the POST attribute is None, it means that the request is a GET
       request and hence if there are any values stored in the instance
       those values are returned

    Args:
      field: the name of the field
    """
    if self.request_data.request.method == 'POST':
      initial = self.POST.getlist(field)
      return initial if initial else []

    if self.instance:
      return [str(t) for t in getattr(self.instance, field)]

    return []

  def _saveTags(self, entity):
    entity.arbit_tag = {
        'tags': self.cleaned_data['tags'],
        'scope': self.request_data.program,
        }

  def save(self, commit=True):
    self.cleaned_data['modified_by'] = self.request_data.profile

    entity = super(TaskEditPostClaimForm, self).save(commit=False)

    if commit:
      entity.put()

    if entity:
      self._saveTags(entity)

    return entity

  def clean_mentors(self):
    mentor_key_strs = self.data.getlist('mentors')

    if not mentor_key_strs:
      raise django_forms.ValidationError(
          ugettext("At least one mentor should be assigned to the task."))

    org_mentors_keys = profile_logic.queryAllMentorsForOrg(
        self.organization, keys_only=True)

    mentor_keys = []
    for m_str in mentor_key_strs:
      if not m_str:
        break

      mentor_key = db.Key(m_str)
      if mentor_key not in org_mentors_keys:
        raise django_forms.ValidationError(
            ugettext("One of the mentors doesn't belong to the organization "
                     "that this task belongs to."))

      mentor_keys.append(mentor_key)

    return mentor_keys

  class Meta:
    model = task.GCITask
    css_prefix = 'gci-task'
    fields = ['arbit_tag']

class TaskCreateForm(TaskEditPostClaimForm):
  """Django form for the task creation page.
  """

  time_to_complete_days = django_forms.IntegerField(
      label=ugettext('Time to complete'), min_value=0,
      error_messages={'min_value': ugettext('Days cannot be negative.')})

  time_to_complete_hours = django_forms.IntegerField(
      label=ugettext('Time to complete'), min_value=0,
      error_messages={'min_value': ugettext('Hours cannot be negative.')})

  def __init__(self, data, *args, **kwargs):
    super(TaskCreateForm, self).__init__(data, *args, **kwargs)

    difficulties = [(d, d) for d in DIFFICULTIES[:-1]]
    self.fields['difficulty_level'] = django_forms.ChoiceField(
        label=ugettext('Difficulty'), choices=difficulties)

    # get a list of task type tags stored for the program entity
    type_tags = task.TaskTypeTag.get_by_scope(data.program)

    task_type_tags = []
    for type_tag in type_tags:
      task_type_tags.append((type_tag.tag, type_tag.tag))

    self.fields['task_type'] = django_forms.MultipleChoiceField(
        label=ugettext('Type'), choices=task_type_tags,
        widget=forms.CheckboxSelectMultiple)

    self.fields['task_type'].initial = self._getInitialValuesForList(
        'task_type')

    if self.instance:
      ttc = datetime.timedelta(hours=self.instance.time_to_complete)
      self.fields['time_to_complete_days'].initial = ttc.days
      self.fields['time_to_complete_hours'].initial = ttc.seconds / 3600

      self.fields['difficulty_level'].initial = self.instance.difficulty_level

    # Bind all the fields here to boundclass since we do not iterate
    # over the fields using iterator for this form.
    for name, field in self.fields.items():
      self.bound_fields[name] = gci_forms.GCIBoundField(self, field, name)

  def _saveTags(self, entity):
    super(TaskCreateForm, self)._saveTags(entity)

    entity.task_type = {
        'tags': self.cleaned_data['task_type'],
        'scope': self.request_data.program,
        }

  def create(self, commit=True, key_name=None, parent=None):
    # organization and status are in this create method and not in cleaner
    # because we want to store it in the entity only when it is created an
    # not while editing.
    organization = self.organization
    self.cleaned_data['org'] = organization

    profile = self.request_data.profile
    self.cleaned_data['created_by'] = profile
    self.cleaned_data['modified_by'] = profile

    entity = super(TaskCreateForm, self).create(
        commit=False, key_name=key_name, parent=parent)

    if commit:
      entity.put()

    if organization.key() in self.request_data.org_admin_for:
      entity.status = 'Unpublished'
    elif organization.key() in self.request_data.mentor_for:
      entity.status = 'Unapproved'

    if entity:
      self._saveTags(entity)

    return entity

  clean_description = cleaning.clean_html_content('description')

  def clean(self):
    super(TaskCreateForm, self).clean()

    cleaned_data = self.cleaned_data
    ttc_days = cleaned_data.get("time_to_complete_days", 0)
    ttc_hours = cleaned_data.get("time_to_complete_hours", 0)

    if ttc_days or ttc_hours:
      cleaned_data['time_to_complete'] = ttc_days * 24 + ttc_hours
    else:
      raise django_forms.ValidationError(
          ugettext('Time to complete must be specified.'))

    # Disallow "Unknown" difficulty
    if 'difficulty' in cleaned_data and \
        cleaned_data['difficulty'] not in DIFFICULTIES[:-1]:
      raise django_forms.ValidationError('Unknown difficulty is not supported')

    return cleaned_data

  class Meta:
    model = task.GCITask
    css_prefix = 'gci-task'
    fields = ['title', 'description', 'difficulty_level',
              'task_type', 'arbit_tag']

class TaskFormErrorTemplate(Template):
  """Task forms error message template.
  """

  def __init__(self, data, error):
    self.data = data
    self.error = error

  def context(self):
    return {
      'error': self.error,
    }

  def templatePath(self):
    return "v2/modules/gci/task_create/_error_msg.html"

class TaskEditFormTemplate(Template):
  """Task edit form template to use.
  """

  def __init__(self, data):
    self.data = data

  def context(self):
    if self.data.task:
      if self.data.full_edit:
        form_class = TaskCreateForm
      else:
        form_class = TaskEditPostClaimForm

      form = form_class(self.data, self.data.POST or None,
                        instance=self.data.task)
      title = "Edit task - %s" % (self.data.task.title)
    else:
      form = TaskCreateForm(self.data, self.data.POST or None)
      title = "Create a new task"

    return {
      'title':  title,
      'form': form,
      'full_edit': self.data.full_edit,
      'error': TaskFormErrorTemplate(self.data, form.errors),
    }

  def templatePath(self):
    if self.data.task and not self.data.full_edit:
      return "v2/modules/gci/task_create/_post_claim_edit.html"
    else:
      return "v2/modules/gci/task_create/_full_edit.html"

class TaskCreatePage(RequestHandler):
  """View to create a new task.
  """

  def djangoURLPatterns(self):
    return [
        url(r'task/create/%s$' % url_patterns.ORG,
            self, name='gci_create_task'),
        url(r'task/edit/%s$' % url_patterns.ID,
            self, name='gci_edit_task'),
    ]

  def checkAccess(self):
    self.mutator.taskFromKwargsIfId()

    self.check.isLoggedIn()

    assert access_checker.isSet(self.data.task)

    if self.data.task:
      self.check.checkCanUserEditTask()
      self.check.checkTimelineAllowsTaskEditing()

      # Set full_edit status depending on the task status
      self.mutator.fullEdit(self.check.hasTaskEditableStatus())
    else:
      self.check.canCreateTask()

  def templatePath(self):
    return 'v2/modules/gci/task_create/base.html'

  def context(self):
    if self.data.task:
      page_name = "Edit task - %s" % (self.data.task.title)
    else:
      page_name = "Create a new task"

    return {
      'page_name':  page_name,
      'task_edit_form_template': TaskEditFormTemplate(self.data),
    }

  def createTaskFromForm(self):
    """Creates a new task based on the data inserted in the form.

    Returns:
      a newly created task entity or None.
    """
    if self.data.task:
      if self.data.full_edit:
        form_class = TaskCreateForm
      else:
        form_class = TaskEditPostClaimForm

      form = form_class(self.data, self.data.POST, instance=self.data.task)
    else:
      form = TaskCreateForm(self.data, self.data.POST)

    if not form.is_valid():
      return None

    form.cleaned_data['program'] = self.data.program

    # The creator of the task and all the mentors for the task who have
    # have enabled "Subscribe automatically for the tasks" should be
    # subscribed to this task.
    mentor_keys = form.cleaned_data.get('mentors', None)
    mentor_entities = db.get(mentor_keys)
    subscribers = mentor_entities + [self.data.profile]

    keys = [i.key() for i in subscribers if i.automatic_task_subscription]

    form.cleaned_data['subscribers'] = list(set(keys))

    if not self.data.task:
      entity = form.create(commit=True)
    else:
      entity = form.save(commit=True)

    return entity

  def post(self):
    task = self.createTaskFromForm()
    if task:
      r = self.redirect.id(id=task.key().id_or_name())
      r.to('gci_edit_task', validated=True)
    else:
      self.get()
<commit_msg>List mentors in the list of fields so that initial values are automatically taken care of.<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Views for creating/editing GCI Tasks.
"""

import datetime

from google.appengine.ext import db

from django import forms as django_forms
from django.utils.translation import ugettext

from soc.logic import cleaning
from soc.views import forms
from soc.views.helper import access_checker
from soc.views.helper import url_patterns
from soc.views.template import Template

from soc.modules.gci.logic import profile as profile_logic
from soc.modules.gci.models import task
from soc.modules.gci.models.task import DIFFICULTIES
from soc.modules.gci.models.organization import GCIOrganization
from soc.modules.gci.models.profile import GCIProfile
from soc.modules.gci.views import forms as gci_forms
from soc.modules.gci.views.base import RequestHandler
from soc.modules.gci.views.helper.url_patterns import url

def mentorChoicesForOrg(task, org):
  """Builds the tuple of mentor choice 2-tuples for the Django choice field.

  Args:
    task: GCITask entity for which the create page is being created
    org: The organization entity for which the mentor choices should be
         constructed.
  """
  mentors = profile_logic.queryAllMentorsForOrg(org)
  return ((str(m.key()), m.name()) for m in mentors)

class TaskEditPostClaimForm(gci_forms.GCIModelForm):
  """Django form for the task editing after the task is published page.
  """

  tags = django_forms.CharField(
      label=ugettext('Tags'),
      help_text=ugettext('Describe this task with tags (comma separated). '
                         'Ex: Linux, Apache, C++, GUI'))

  def __init__(self, data, *args, **kwargs):
    super(TaskEditPostClaimForm, self).__init__(*args, **kwargs)

    self.request_data = data
    self.organization = self.request_data.organization if not self.instance \
        else self.instance.org

    self.POST = args[0] if len(args) > 0 and args[0] else None

    mentor_choices = list(mentorChoicesForOrg(self.instance, self.organization))

    self.fields['mentors'] = django_forms.MultipleChoiceField(
        label=ugettext('Mentors'), required=False,
        widget=gci_forms.MultipleSelectWidget(
        attrs={
            'select_id': 'assign-mentor',
            'wrapper_id': 'select-mentors-wrapper',
            'add_new_text': 'add another mentor',
            }, disabled_option=('', 'Select a mentor')),
        choices=mentor_choices)

    if self.instance:
      self.fields['tags'].initial = self.instance.tags_string(
          self.instance.arbit_tag)

    # Bind all the fields here to boundclass since we do not iterate
    # over the fields using iterator for this form.
    self.bound_fields = {}
    for name, field in self.fields.items():
      self.bound_fields[name] = gci_forms.GCIBoundField(self, field, name)

  def _getInitialValuesForList(self, field):
    """Returns the initial values for the field which take list of values.

    One of the following 3 cases can happen:
    1. If POST attribute exists and there are are no values for the given
       field empty list is returned.
    2. It checks if the POST data contains some value(s) for the given field,
       if so the method returns that as the intial value.
    3. If the POST attribute is None, it means that the request is a GET
       request and hence if there are any values stored in the instance
       those values are returned

    Args:
      field: the name of the field
    """
    if self.request_data.request.method == 'POST':
      initial = self.POST.getlist(field)
      return initial if initial else []

    if self.instance:
      return [str(t) for t in getattr(self.instance, field)]

    return []

  def _saveTags(self, entity):
    entity.arbit_tag = {
        'tags': self.cleaned_data['tags'],
        'scope': self.request_data.program,
        }

  def save(self, commit=True):
    self.cleaned_data['modified_by'] = self.request_data.profile

    entity = super(TaskEditPostClaimForm, self).save(commit=False)

    if commit:
      entity.put()

    if entity:
      self._saveTags(entity)

    return entity

  def clean_mentors(self):
    mentor_key_strs = self.data.getlist('mentors')

    if not mentor_key_strs:
      raise django_forms.ValidationError(
          ugettext("At least one mentor should be assigned to the task."))

    org_mentors_keys = profile_logic.queryAllMentorsForOrg(
        self.organization, keys_only=True)

    mentor_keys = []
    for m_str in mentor_key_strs:
      if not m_str:
        break

      mentor_key = db.Key(m_str)
      if mentor_key not in org_mentors_keys:
        raise django_forms.ValidationError(
            ugettext("One of the mentors doesn't belong to the organization "
                     "that this task belongs to."))

      mentor_keys.append(mentor_key)

    return mentor_keys

  class Meta:
    model = task.GCITask
    css_prefix = 'gci-task'
    fields = ['arbit_tag', 'mentors']

class TaskCreateForm(TaskEditPostClaimForm):
  """Django form for the task creation page.
  """

  time_to_complete_days = django_forms.IntegerField(
      label=ugettext('Time to complete'), min_value=0,
      error_messages={'min_value': ugettext('Days cannot be negative.')})

  time_to_complete_hours = django_forms.IntegerField(
      label=ugettext('Time to complete'), min_value=0,
      error_messages={'min_value': ugettext('Hours cannot be negative.')})

  def __init__(self, data, *args, **kwargs):
    super(TaskCreateForm, self).__init__(data, *args, **kwargs)

    difficulties = [(d, d) for d in DIFFICULTIES[:-1]]
    self.fields['difficulty_level'] = django_forms.ChoiceField(
        label=ugettext('Difficulty'), choices=difficulties)

    # get a list of task type tags stored for the program entity
    type_tags = task.TaskTypeTag.get_by_scope(data.program)

    task_type_tags = []
    for type_tag in type_tags:
      task_type_tags.append((type_tag.tag, type_tag.tag))

    self.fields['task_type'] = django_forms.MultipleChoiceField(
        label=ugettext('Type'), choices=task_type_tags,
        widget=forms.CheckboxSelectMultiple)

    self.fields['task_type'].initial = self._getInitialValuesForList(
        'task_type')

    if self.instance:
      ttc = datetime.timedelta(hours=self.instance.time_to_complete)
      self.fields['time_to_complete_days'].initial = ttc.days
      self.fields['time_to_complete_hours'].initial = ttc.seconds / 3600

      self.fields['difficulty_level'].initial = self.instance.difficulty_level

    # Bind all the fields here to boundclass since we do not iterate
    # over the fields using iterator for this form.
    for name, field in self.fields.items():
      self.bound_fields[name] = gci_forms.GCIBoundField(self, field, name)

  def _saveTags(self, entity):
    super(TaskCreateForm, self)._saveTags(entity)

    entity.task_type = {
        'tags': self.cleaned_data['task_type'],
        'scope': self.request_data.program,
        }

  def create(self, commit=True, key_name=None, parent=None):
    # organization and status are in this create method and not in cleaner
    # because we want to store it in the entity only when it is created an
    # not while editing.
    organization = self.organization
    self.cleaned_data['org'] = organization

    profile = self.request_data.profile
    self.cleaned_data['created_by'] = profile
    self.cleaned_data['modified_by'] = profile

    entity = super(TaskCreateForm, self).create(
        commit=False, key_name=key_name, parent=parent)

    if commit:
      entity.put()

    if organization.key() in self.request_data.org_admin_for:
      entity.status = 'Unpublished'
    elif organization.key() in self.request_data.mentor_for:
      entity.status = 'Unapproved'

    if entity:
      self._saveTags(entity)

    return entity

  clean_description = cleaning.clean_html_content('description')

  def clean(self):
    super(TaskCreateForm, self).clean()

    cleaned_data = self.cleaned_data
    ttc_days = cleaned_data.get("time_to_complete_days", 0)
    ttc_hours = cleaned_data.get("time_to_complete_hours", 0)

    if ttc_days or ttc_hours:
      cleaned_data['time_to_complete'] = ttc_days * 24 + ttc_hours
    else:
      raise django_forms.ValidationError(
          ugettext('Time to complete must be specified.'))

    # Disallow "Unknown" difficulty
    if 'difficulty' in cleaned_data and \
        cleaned_data['difficulty'] not in DIFFICULTIES[:-1]:
      raise django_forms.ValidationError('Unknown difficulty is not supported')

    return cleaned_data

  class Meta:
    model = task.GCITask
    css_prefix = 'gci-task'
    fields = ['title', 'description', 'difficulty_level',
              'task_type', 'arbit_tag', 'mentors']

class TaskFormErrorTemplate(Template):
  """Task forms error message template.
  """

  def __init__(self, data, error):
    self.data = data
    self.error = error

  def context(self):
    return {
      'error': self.error,
    }

  def templatePath(self):
    return "v2/modules/gci/task_create/_error_msg.html"

class TaskEditFormTemplate(Template):
  """Task edit form template to use.
  """

  def __init__(self, data):
    self.data = data

  def context(self):
    if self.data.task:
      if self.data.full_edit:
        form_class = TaskCreateForm
      else:
        form_class = TaskEditPostClaimForm

      form = form_class(self.data, self.data.POST or None,
                        instance=self.data.task)
      title = "Edit task - %s" % (self.data.task.title)
    else:
      form = TaskCreateForm(self.data, self.data.POST or None)
      title = "Create a new task"

    return {
      'title':  title,
      'form': form,
      'full_edit': self.data.full_edit,
      'error': TaskFormErrorTemplate(self.data, form.errors),
    }

  def templatePath(self):
    if self.data.task and not self.data.full_edit:
      return "v2/modules/gci/task_create/_post_claim_edit.html"
    else:
      return "v2/modules/gci/task_create/_full_edit.html"

class TaskCreatePage(RequestHandler):
  """View to create a new task.
  """

  def djangoURLPatterns(self):
    return [
        url(r'task/create/%s$' % url_patterns.ORG,
            self, name='gci_create_task'),
        url(r'task/edit/%s$' % url_patterns.ID,
            self, name='gci_edit_task'),
    ]

  def checkAccess(self):
    self.mutator.taskFromKwargsIfId()

    self.check.isLoggedIn()

    assert access_checker.isSet(self.data.task)

    if self.data.task:
      self.check.checkCanUserEditTask()
      self.check.checkTimelineAllowsTaskEditing()

      # Set full_edit status depending on the task status
      self.mutator.fullEdit(self.check.hasTaskEditableStatus())
    else:
      self.check.canCreateTask()

  def templatePath(self):
    return 'v2/modules/gci/task_create/base.html'

  def context(self):
    if self.data.task:
      page_name = "Edit task - %s" % (self.data.task.title)
    else:
      page_name = "Create a new task"

    return {
      'page_name':  page_name,
      'task_edit_form_template': TaskEditFormTemplate(self.data),
    }

  def createTaskFromForm(self):
    """Creates a new task based on the data inserted in the form.

    Returns:
      a newly created task entity or None.
    """
    if self.data.task:
      if self.data.full_edit:
        form_class = TaskCreateForm
      else:
        form_class = TaskEditPostClaimForm

      form = form_class(self.data, self.data.POST, instance=self.data.task)
    else:
      form = TaskCreateForm(self.data, self.data.POST)

    if not form.is_valid():
      return None

    form.cleaned_data['program'] = self.data.program

    # The creator of the task and all the mentors for the task who have
    # have enabled "Subscribe automatically for the tasks" should be
    # subscribed to this task.
    mentor_keys = form.cleaned_data.get('mentors', None)
    mentor_entities = db.get(mentor_keys)
    subscribers = mentor_entities + [self.data.profile]

    keys = [i.key() for i in subscribers if i.automatic_task_subscription]

    form.cleaned_data['subscribers'] = list(set(keys))

    if not self.data.task:
      entity = form.create(commit=True)
    else:
      entity = form.save(commit=True)

    return entity

  def post(self):
    task = self.createTaskFromForm()
    if task:
      r = self.redirect.id(id=task.key().id_or_name())
      r.to('gci_edit_task', validated=True)
    else:
      self.get()
<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""The role conversion updates are defined in this module.
"""

__authors__ = [
    '"Daniel Hans" <daniel.m.hans@gmail.com>',
  ]

import gae_django

from google.appengine.ext import db
from google.appengine.ext import deferred
from google.appengine.runtime import DeadlineExceededError

from django import http

from soc.models.host import Host
from soc.models.linkable import Linkable
from soc.models.mentor import Mentor
from soc.models.org_admin import OrgAdmin
from soc.models.role import StudentInfo

from soc.modules.gsoc.models.mentor import GSoCMentor
from soc.modules.gsoc.models.organization import GSoCOrganization
from soc.modules.gsoc.models.org_admin import GSoCOrgAdmin
from soc.modules.gsoc.models.profile import GSoCProfile
from soc.modules.gsoc.models.program import GSoCProgram
from soc.modules.gsoc.models.project import GSoCProject
from soc.modules.gsoc.models.proposal import GSoCProposal
from soc.modules.gsoc.models.student import GSoCStudent
from soc.modules.gsoc.models.profile import GSoCStudentInfo
from soc.modules.gsoc.models.student_project import StudentProject
from soc.modules.gsoc.models.student_proposal import StudentProposal

ROLE_MODELS = [GSoCMentor, GSoCOrgAdmin, GSoCStudent]

def getDjangoURLPatterns():
  """Returns the URL patterns for the tasks in this module.
  """

  patterns = [
      (r'^tasks/role_conversion/update_references',
        'soc.tasks.updates.role_conversion.updateReferences'),
      (r'^tasks/role_conversion/update_project_references',
        'soc.tasks.updates.role_conversion.updateStudentProjectReferences'),
      (r'^tasks/role_conversion/update_proposal_references',
        'soc.tasks.updates.role_conversion.updateStudentProposalReferences'),
      (r'^tasks/role_conversion/update_roles$',
        'soc.tasks.updates.role_conversion.updateRoles'),
      (r'^tasks/role_conversion/update_mentors$',
        'soc.tasks.updates.role_conversion.updateMentors'),
      (r'^tasks/role_conversion/update_org_admins$',
        'soc.tasks.updates.role_conversion.updateOrgAdmins'),
      (r'^tasks/role_conversion/update_students$',
        'soc.tasks.updates.role_conversion.updateStudents'),
      (r'^tasks/role_conversion/update_hosts$',
        'soc.tasks.updates.role_conversion.updateHosts'),
      (r'^tasks/role_conversion/update_student_infos$',
        'soc.tasks.updates.role_conversion.updateStudentInfos'),
  ]

  return patterns

class HostUpdater(object):
  """Class which is responsible for updating Host entities.
  """

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _process(self, start_key, batch_size):
    """Retrieves Host entities and updates them.
    """

    query = Host.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        sponsor = entity.scope
        host_for = entity.user.host_for

        if not host_for:
          host_for = []

        user = entity.user
        if sponsor.key() not in host_for:
          host_for.append(sponsor.key())
        user.host_for = host_for

        db.put(user)

      # process the next batch of entities
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

class RoleUpdater(object):
  """Class which is responsible for updating the entities.
  """

  POPULATED_PROFILE_PROPS = set(
      GSoCProfile.properties()) - set(Linkable.properties())

  POPULATED_STUDENT_PROPS = StudentInfo.properties()

  def __init__(self, model, profile_model, student_model,
               studentinfo_model, program_field, role_field=None):
    self.MODEL = model
    self.PROFILE_MODEL = profile_model
    self.PROGRAM_FIELD = program_field
    self.ROLE_FIELD = role_field
    self.STUDENT_MODEL = student_model
    self.STUDENTINFO_MODEL = studentinfo_model

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _prcoessStudentEntity(self, entity, **properties):
    pass

  def _processEntity(self, entity):
    program = getattr(entity, self.PROGRAM_FIELD)
    user = entity.user

    # try to find an existing Profile entity or create a new one
    key_name = program.key().name() + '/' + user.link_id
    properties = {
        'link_id': entity.link_id,
        'scope_path': program.key().name(),
        'scope': program,
        'parent': user,
        }
    for prop in self.POPULATED_PROFILE_PROPS:
      properties[prop] = getattr(entity, prop)

    profile = self.PROFILE_MODEL.get_or_insert(
        key_name=key_name, **properties)

    # do not update anything if the role is already in the profile
    if profile.student_info and self.MODEL == self.STUDENT_MODEL:
      return
    elif self.ROLE_FIELD:
      if entity.scope.key() in getattr(profile, self.ROLE_FIELD):
        return

    to_put = [profile]

    # a non-invalid role is found, we should re-populate the profile
    if profile.status == 'invalid' and entity.status != 'invalid':
      for prop_name in entity.properties():
        value = getattr(entity, prop_name)
        setattr(profile, prop_name, value)

      if profile.student_info:
        profile.student_info = None

    if self.ROLE_FIELD:
      # the role is either Mentor or OrgAdmin
      getattr(profile, self.ROLE_FIELD).append(entity.scope.key())
    else:
      # the role is certainly Student; we have to create a new StudentInfo
      properties = {}
      for prop in self.POPULATED_STUDENT_PROPS:
        properties[prop] = getattr(entity, prop)
      self._processStudentEntity(entity, properties)

      key_name = profile.key().name()
      student_info = self.STUDENTINFO_MODEL(key_name=key_name,
          parent=profile, **properties)
      profile.student_info = student_info
      to_put.append(student_info)

    db.run_in_transaction(db.put, to_put)

  def _process(self, start_key, batch_size):
    """Retrieves entities and creates or updates a corresponding
    Profile entity.
    """

    query = self.MODEL.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        try:
          self._processEntity(entity)
        except db.Error, e:
          import logging
          logging.exception(e)
          logging.error("Broke on %s: %s" % (entity.key().name(), self.MODEL))

      # process the next batch of entities
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

class StudentInfoUpdater(object):
  """Class which is responsible for creating GSoCStudentInfo based on
  the corresponding StudentInfo entities
  """

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _processEntity(self, entity):
    profile = entity.parent()
    project = GSoCProject.all().ancestor(profile).get()

    properties = {
        'school_name': entity.school_name,
        'school_country': entity.school_country,
        'school_home_page': entity.school_home_page,
        'school_type': entity.school_type,
        'major': entity.major,
        'degree': entity.degree,
        'expected_graduation': entity.expected_graduation,
        'number_of_proposals': GSoCProposal.all().ancestor(profile).count(),
        'number_of_projects': 1 if project is not None else 0,
        'project_for_orgs': [project.org.key()] if project else []
        }

    studentInfo = GSoCStudentInfo(key_name = profile.key().name(),
        parent=profile, **properties)
    profile.student_info = studentInfo

    db.run_in_transaction(db.put, [profile, studentInfo])

  def _process(self, start_key, batch_size):
    """Retrieves entities and creates or updates a corresponding
    Profile entity.
    """

    query = StudentInfo.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        try:
          self._processEntity(entity)
        except db.Error, e:
          import logging
          logging.exception(e)
          logging.error("Broke on %s: %s" % (entity.key().name(), 'StudentInfo'))

      # process the next batch of entities
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

def updateHosts(request):
  """Starts a task which updates Host entities.
  """

  updater = HostUpdater()
  updater.run()
  return http.HttpResponse("Ok")

def updateStudentInfos(request):
  """Starts a task which updates StudentInfo entities
  """

  updater = StudentInfoUpdater()
  updater.run()
  return http.HttpResponse("Ok")

def updateRole(role_name):
  """Starts a task which updates a particular role.
  """

  if role_name == 'gsoc_mentor':
    updater = RoleUpdater(GSoCMentor, GSoCProfile,
        GSoCStudent, GSoCStudentInfo, 'program', 'mentor_for')
  elif role_name == 'gsoc_org_admin':
    updater = RoleUpdater(GSoCOrgAdmin, GSoCProfile,
        GSoCStudent, GSoCStudentInfo, 'program', 'org_admin_for')
  elif role_name == 'gsoc_student':
    updater = RoleUpdater(GSoCStudent, GSoCProfile,
        GSoCStudent, GSoCStudentInfo, 'scope')

  updater.run()
  return http.HttpResponse("Ok")

def updateRoles(request):
  """Starts a bunch of iterative tasks which update particular roles.

  In order to prevent issues with concurrent access to entities, we set
  ETA so that each role is processed in separation.
  """

  # update org admins
  #updateRole('gsoc_org_admin')

  # update mentors
  #updateRole('gsoc_mentor')

  # update students
  # we can assume that students cannot have any other roles, so we do not
  # need to set ETA
  updateRole('gsoc_student')

def updateMentors(request):
  """Starts an iterative task which update mentors.
  """

  return updateRole('gsoc_mentor')

def updateOrgAdmins(request):
  """Starts an iterative task which update org admins.
  """

  return updateRole('gsoc_org_admin')

def updateStudents(request):
  """Starts an iterative task which update students.
  """

  return updateRole('gsoc_student')

def _getProfileForRole(entity, profile_model):
  """Returns GSoCProfile or GCIProfile which corresponds to the specified
  entity.
  """

  if isinstance(entity, profile_model):
    return entity

  if isinstance(entity, OrgAdmin) or isinstance(entity, Mentor):
    key_name = entity.program.key().name() + '/' + entity.user.key().name()
  else:
    key_name = entity.key().name()

  parent = entity.user
  return profile_model.get_by_key_name(key_name, parent=parent)

def _getProfileKeyForRoleKey(key, profile_model):
  """Returns Key instance of the Profile which corresponds to the Role which
  is represented by the specified Key.
  """

  entity = db.get(key)
  profile = _getProfileForRole(entity, profile_model)
  return profile.key()

class ReferenceUpdater(object):
  """Class which is responsible for updating references to Profile in
  the specified model.
  """

  def __init__(self, model, profile_model, fields_to_update,
               lists_to_update=[]):
    self.MODEL = model
    self.PROFILE_MODEL = profile_model
    self.FIELDS_TO_UPDATE = fields_to_update
    self.LISTS_TO_UPDATE = lists_to_update

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _process(self, start_key, batch_size):
    """Iterates through the entities and updates the references.
    """

    query = self.MODEL.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        for field in self.FIELDS_TO_UPDATE:
          old_reference = getattr(entity, field)

          if not old_reference:
            continue

          # check if the field has not been updated
          if isinstance(old_reference, self.PROFILE_MODEL):
            continue

          profile = _getProfileForRole(old_reference, self.PROFILE_MODEL)
          setattr(entity, field, profile)

        for list_property in self.LISTS_TO_UPDATE:
          l = getattr(entity, list_property)
          new_l = []
          for key in l:
            new_l.append(_getProfileKeyForRoleKey(key, self.PROFILE_MODEL))
          setattr(entity, list_property, new_l)

      db.put(entities)
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

def updateReferencesForModel(model):
  """Starts a task which updates references for a particular model.
  """

  if model == 'student_proposal':
    updater = ReferenceUpdater(StudentProposal, GSoCProfile,
        ['scope', 'mentor'], ['possible_mentors'])
  elif model == 'student_project':
    updater = ReferenceUpdater(StudentProject, GSoCProfile,
        ['mentor', 'student'], ['additional_mentors'])

  updater.run()
  return http.HttpResponse("Ok")

def updateStudentProjectReferences(request):
  """Starts a bunch of iterative tasks which update references in
  StudentProjects.
  """

  return updateReferencesForModel('student_project')

def updateStudentProposalReferences(request):
  """Starts a bunch of iterative tasks which update references in
  StudentProposals.
  """

  return updateReferencesForModel('student_proposal')

def updateReferences(request):
  """Starts a bunch of iterative tasks which update references to various roles.
  """

  # updates student proposals
  updateReferencesForModel('student_proposal')

  # updates student projects
  updateReferencesForModel('student_project')

  return http.HttpResponse("Ok")
<commit_msg>Do not populate properties that did not exist in the old models.<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""The role conversion updates are defined in this module.
"""

__authors__ = [
    '"Daniel Hans" <daniel.m.hans@gmail.com>',
  ]

import gae_django

from google.appengine.ext import db
from google.appengine.ext import deferred
from google.appengine.runtime import DeadlineExceededError

from django import http

from soc.models.host import Host
from soc.models.linkable import Linkable
from soc.models.mentor import Mentor
from soc.models.org_admin import OrgAdmin
from soc.models.role import StudentInfo

from soc.modules.gsoc.models.mentor import GSoCMentor
from soc.modules.gsoc.models.organization import GSoCOrganization
from soc.modules.gsoc.models.org_admin import GSoCOrgAdmin
from soc.modules.gsoc.models.profile import GSoCProfile
from soc.modules.gsoc.models.program import GSoCProgram
from soc.modules.gsoc.models.project import GSoCProject
from soc.modules.gsoc.models.proposal import GSoCProposal
from soc.modules.gsoc.models.student import GSoCStudent
from soc.modules.gsoc.models.profile import GSoCStudentInfo
from soc.modules.gsoc.models.student_project import StudentProject
from soc.modules.gsoc.models.student_proposal import StudentProposal

ROLE_MODELS = [GSoCMentor, GSoCOrgAdmin, GSoCStudent]

def getDjangoURLPatterns():
  """Returns the URL patterns for the tasks in this module.
  """

  patterns = [
      (r'^tasks/role_conversion/update_references',
        'soc.tasks.updates.role_conversion.updateReferences'),
      (r'^tasks/role_conversion/update_project_references',
        'soc.tasks.updates.role_conversion.updateStudentProjectReferences'),
      (r'^tasks/role_conversion/update_proposal_references',
        'soc.tasks.updates.role_conversion.updateStudentProposalReferences'),
      (r'^tasks/role_conversion/update_roles$',
        'soc.tasks.updates.role_conversion.updateRoles'),
      (r'^tasks/role_conversion/update_mentors$',
        'soc.tasks.updates.role_conversion.updateMentors'),
      (r'^tasks/role_conversion/update_org_admins$',
        'soc.tasks.updates.role_conversion.updateOrgAdmins'),
      (r'^tasks/role_conversion/update_students$',
        'soc.tasks.updates.role_conversion.updateStudents'),
      (r'^tasks/role_conversion/update_hosts$',
        'soc.tasks.updates.role_conversion.updateHosts'),
      (r'^tasks/role_conversion/update_student_infos$',
        'soc.tasks.updates.role_conversion.updateStudentInfos'),
  ]

  return patterns

class HostUpdater(object):
  """Class which is responsible for updating Host entities.
  """

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _process(self, start_key, batch_size):
    """Retrieves Host entities and updates them.
    """

    query = Host.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        sponsor = entity.scope
        host_for = entity.user.host_for

        if not host_for:
          host_for = []

        user = entity.user
        if sponsor.key() not in host_for:
          host_for.append(sponsor.key())
        user.host_for = host_for

        db.put(user)

      # process the next batch of entities
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

class RoleUpdater(object):
  """Class which is responsible for updating the entities.
  """

  POPULATED_PROFILE_PROPS = set(
      GSoCProfile.properties()) - set(Linkable.properties())

  POPULATED_STUDENT_PROPS = StudentInfo.properties()

  def __init__(self, model, profile_model, student_model,
               studentinfo_model, program_field, role_field=None):
    self.MODEL = model
    self.PROFILE_MODEL = profile_model
    self.PROGRAM_FIELD = program_field
    self.ROLE_FIELD = role_field
    self.STUDENT_MODEL = student_model
    self.STUDENTINFO_MODEL = studentinfo_model

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _prcoessStudentEntity(self, entity, **properties):
    pass

  def _processEntity(self, entity):
    program = getattr(entity, self.PROGRAM_FIELD)
    user = entity.user

    # try to find an existing Profile entity or create a new one
    key_name = program.key().name() + '/' + user.link_id
    properties = {
        'link_id': entity.link_id,
        'scope_path': program.key().name(),
        'scope': program,
        'parent': user,
        }
    for prop in self.POPULATED_PROFILE_PROPS:
      if hasattr(entity, prop):
        properties[prop] = getattr(entity, prop)

    profile = self.PROFILE_MODEL.get_or_insert(
        key_name=key_name, **properties)

    # do not update anything if the role is already in the profile
    if profile.student_info and self.MODEL == self.STUDENT_MODEL:
      return
    elif self.ROLE_FIELD:
      if entity.scope.key() in getattr(profile, self.ROLE_FIELD):
        return

    to_put = [profile]

    # a non-invalid role is found, we should re-populate the profile
    if profile.status == 'invalid' and entity.status != 'invalid':
      for prop_name in entity.properties():
        value = getattr(entity, prop_name)
        setattr(profile, prop_name, value)

      if profile.student_info:
        profile.student_info = None

    if self.ROLE_FIELD:
      # the role is either Mentor or OrgAdmin
      getattr(profile, self.ROLE_FIELD).append(entity.scope.key())
    else:
      # the role is certainly Student; we have to create a new StudentInfo
      properties = {}
      for prop in self.POPULATED_STUDENT_PROPS:
        if hasattr(entity, prop):
          properties[prop] = getattr(entity, prop)
      self._processStudentEntity(entity, properties)

      key_name = profile.key().name()
      student_info = self.STUDENTINFO_MODEL(key_name=key_name,
          parent=profile, **properties)
      profile.student_info = student_info
      to_put.append(student_info)

    db.run_in_transaction(db.put, to_put)

  def _process(self, start_key, batch_size):
    """Retrieves entities and creates or updates a corresponding
    Profile entity.
    """

    query = self.MODEL.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        try:
          self._processEntity(entity)
        except db.Error, e:
          import logging
          logging.exception(e)
          logging.error("Broke on %s: %s" % (entity.key().name(), self.MODEL))

      # process the next batch of entities
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

class StudentInfoUpdater(object):
  """Class which is responsible for creating GSoCStudentInfo based on
  the corresponding StudentInfo entities
  """

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _processEntity(self, entity):
    profile = entity.parent()
    project = GSoCProject.all().ancestor(profile).get()

    properties = {
        'school_name': entity.school_name,
        'school_country': entity.school_country,
        'school_home_page': entity.school_home_page,
        'school_type': entity.school_type,
        'major': entity.major,
        'degree': entity.degree,
        'expected_graduation': entity.expected_graduation,
        'number_of_proposals': GSoCProposal.all().ancestor(profile).count(),
        'number_of_projects': 1 if project is not None else 0,
        'project_for_orgs': [project.org.key()] if project else []
        }

    studentInfo = GSoCStudentInfo(key_name = profile.key().name(),
        parent=profile, **properties)
    profile.student_info = studentInfo

    db.run_in_transaction(db.put, [profile, studentInfo])

  def _process(self, start_key, batch_size):
    """Retrieves entities and creates or updates a corresponding
    Profile entity.
    """

    query = StudentInfo.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        try:
          self._processEntity(entity)
        except db.Error, e:
          import logging
          logging.exception(e)
          logging.error("Broke on %s: %s" % (entity.key().name(), 'StudentInfo'))

      # process the next batch of entities
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

def updateHosts(request):
  """Starts a task which updates Host entities.
  """

  updater = HostUpdater()
  updater.run()
  return http.HttpResponse("Ok")

def updateStudentInfos(request):
  """Starts a task which updates StudentInfo entities
  """

  updater = StudentInfoUpdater()
  updater.run()
  return http.HttpResponse("Ok")

def updateRole(role_name):
  """Starts a task which updates a particular role.
  """

  if role_name == 'gsoc_mentor':
    updater = RoleUpdater(GSoCMentor, GSoCProfile,
        GSoCStudent, GSoCStudentInfo, 'program', 'mentor_for')
  elif role_name == 'gsoc_org_admin':
    updater = RoleUpdater(GSoCOrgAdmin, GSoCProfile,
        GSoCStudent, GSoCStudentInfo, 'program', 'org_admin_for')
  elif role_name == 'gsoc_student':
    updater = RoleUpdater(GSoCStudent, GSoCProfile,
        GSoCStudent, GSoCStudentInfo, 'scope')

  updater.run()
  return http.HttpResponse("Ok")

def updateRoles(request):
  """Starts a bunch of iterative tasks which update particular roles.

  In order to prevent issues with concurrent access to entities, we set
  ETA so that each role is processed in separation.
  """

  # update org admins
  #updateRole('gsoc_org_admin')

  # update mentors
  #updateRole('gsoc_mentor')

  # update students
  # we can assume that students cannot have any other roles, so we do not
  # need to set ETA
  updateRole('gsoc_student')

def updateMentors(request):
  """Starts an iterative task which update mentors.
  """

  return updateRole('gsoc_mentor')

def updateOrgAdmins(request):
  """Starts an iterative task which update org admins.
  """

  return updateRole('gsoc_org_admin')

def updateStudents(request):
  """Starts an iterative task which update students.
  """

  return updateRole('gsoc_student')

def _getProfileForRole(entity, profile_model):
  """Returns GSoCProfile or GCIProfile which corresponds to the specified
  entity.
  """

  if isinstance(entity, profile_model):
    return entity

  if isinstance(entity, OrgAdmin) or isinstance(entity, Mentor):
    key_name = entity.program.key().name() + '/' + entity.user.key().name()
  else:
    key_name = entity.key().name()

  parent = entity.user
  return profile_model.get_by_key_name(key_name, parent=parent)

def _getProfileKeyForRoleKey(key, profile_model):
  """Returns Key instance of the Profile which corresponds to the Role which
  is represented by the specified Key.
  """

  entity = db.get(key)
  profile = _getProfileForRole(entity, profile_model)
  return profile.key()

class ReferenceUpdater(object):
  """Class which is responsible for updating references to Profile in
  the specified model.
  """

  def __init__(self, model, profile_model, fields_to_update,
               lists_to_update=[]):
    self.MODEL = model
    self.PROFILE_MODEL = profile_model
    self.FIELDS_TO_UPDATE = fields_to_update
    self.LISTS_TO_UPDATE = lists_to_update

  def run(self, batch_size=25):
    """Starts the updater.
    """

    self._process(None, batch_size)

  def _process(self, start_key, batch_size):
    """Iterates through the entities and updates the references.
    """

    query = self.MODEL.all()
    if start_key:
      query.filter('__key__ > ', start_key)

    try:
      entities = query.fetch(batch_size)

      if not entities:
        # all entities has already been processed
        return

      for entity in entities:
        for field in self.FIELDS_TO_UPDATE:
          old_reference = getattr(entity, field)

          if not old_reference:
            continue

          # check if the field has not been updated
          if isinstance(old_reference, self.PROFILE_MODEL):
            continue

          profile = _getProfileForRole(old_reference, self.PROFILE_MODEL)
          setattr(entity, field, profile)

        for list_property in self.LISTS_TO_UPDATE:
          l = getattr(entity, list_property)
          new_l = []
          for key in l:
            new_l.append(_getProfileKeyForRoleKey(key, self.PROFILE_MODEL))
          setattr(entity, list_property, new_l)

      db.put(entities)
      start_key = entities[-1].key()
      deferred.defer(self._process, start_key, batch_size)
    except DeadlineExceededError:
      # here we should probably be more careful
      deferred.defer(self._process, start_key, batch_size)

def updateReferencesForModel(model):
  """Starts a task which updates references for a particular model.
  """

  if model == 'student_proposal':
    updater = ReferenceUpdater(StudentProposal, GSoCProfile,
        ['scope', 'mentor'], ['possible_mentors'])
  elif model == 'student_project':
    updater = ReferenceUpdater(StudentProject, GSoCProfile,
        ['mentor', 'student'], ['additional_mentors'])

  updater.run()
  return http.HttpResponse("Ok")

def updateStudentProjectReferences(request):
  """Starts a bunch of iterative tasks which update references in
  StudentProjects.
  """

  return updateReferencesForModel('student_project')

def updateStudentProposalReferences(request):
  """Starts a bunch of iterative tasks which update references in
  StudentProposals.
  """

  return updateReferencesForModel('student_proposal')

def updateReferences(request):
  """Starts a bunch of iterative tasks which update references to various roles.
  """

  # updates student proposals
  updateReferencesForModel('student_proposal')

  # updates student projects
  updateReferencesForModel('student_project')

  return http.HttpResponse("Ok")
<|endoftext|>


<commit_before>#!/usr/bin/env python

# simple pyCan Example for can4linux
import time
import datetime
import signal
import sys
import subprocess
import struct
import json
import os

sys.path.insert(0, '/root/can4linux-code/can4linux-examples')
import pyCan

# the power expressed in (mW)
# default is around 660
# it must be an Integer greater then 45
# 45mW allows to detect tags at aroud 50cm distance
antennaPower = 2000

datafolder = '/root/slope-data/'
logFolder = '/root/slope-log/'

def get_incremental_number():
	maxcounter = 0
	listFiles = os.listdir(datafolder)
	for file in listFiles:
		if os.path.isfile(datafolder + file):
			name = file.split('_')
			if len(name) > 0:
				counter = name[0]
				if counter.isdigit():
					counter = int(counter)
					if counter > maxcounter:
				 		maxcounter = counter
	return maxcounter + 1

incremental = get_incremental_number()
msgFilePath = datafolder + str(incremental) + '_canbus-messages.txt'
logFilePath = logFolder + 'slope-canbus.log'

def get_lifting_status(status):
	if status == 0:
		return "stop"
	elif status == 1:
		return "going up"
	elif status == 2:
		return "going down"
	else:
		return "error"

def get_translation_status(status):
	if status == 0:
		return "stop"
	elif status == 1:
		return "going to load"
	elif status == 2:
		return "going to release"
	elif status == 3:
		return "antenna down"
	else:
		return "error"

def write_log(text):
	logfile = open(logFilePath, 'a', 1)
	now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
	logfile.write('[' + now + '] ' + text + '\n')
	logfile.close()

def write_msg(text):
	msgfile = open(msgFilePath, 'a+', 1)
	# now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
	msgfile.write(text + '\n')
	msgfile.close()

def get_timestamp():
	return str(int(round(time.time() * 1000)))

def sigterm_handler(_signo, _stack_frame):
	# Raises SystemExit(0):
	sys.exit(0)

signal.signal(signal.SIGTERM, sigterm_handler)

#print 'Python wrapper loaded'
#print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
write_log('Slope-Canbus Version 1.0')
write_log('Python wrapper loaded')
write_log('Incremental Log Number: ' + str(incremental))

# setting the device number
device = 0
defaultBaudrate = '250'

# open the can interface /dev/can0
try:
	fileBaud = open('/proc/sys/dev/Can/Baud', 'r+')
	baudRates = fileBaud.read().split()
	baudRates[device] = defaultBaudrate
	fileBaud.write(' '.join(baudRates))
	fileBaud.close()

except IOError:
	write_log('Could not set the new bitrate')
	exit()

except IndexError:
	write_log('No proper entry for bitrate of can' + str(device) + ' found')
	exit()

# print 'open can'+ str(device) + ' none blocking'
can_fd = pyCan.open(device)

if can_fd == -1:
	write_log('Error opening CAN device /dev/can' + str(device))
	exit()

try:
	write_log('Wait for message...')
	count = 0
	flip = '0'
	lastMsg30 = ""
	lastMsg31 = ""
	lastLifting = 0
	while True:
		data = pyCan.read(can_fd)
		arrMess = data.split(':', 3)
		messId = arrMess[0][:len(arrMess[0]) - 1]
		if messId.isdigit():
			messId = int(messId)
		if messId == 30:
			# print messId
			start = arrMess[1].find("(")
			end = arrMess[1].find(")")
			bytesNum = arrMess[1][start + 1:end]
			# print bytesNum
			messBytes = arrMess[2][1:]
			if messBytes != lastMsg30:  # discard new message if is equal to last one
				lastMsg30 = messBytes
				arrBytes = messBytes.split()
				if bytesNum.isdigit():
					bytesNum = int(bytesNum)
				if bytesNum == len(arrBytes):
					weight = int(struct.unpack('<h', "".join(map(chr, [int(arrBytes[0]), int(arrBytes[1])])))[0])
					# (kg) kilogrammes
					position = int(struct.unpack('<h', "".join(map(chr, [int(arrBytes[2]), int(arrBytes[3])])))[0])
					# (m) meters
					speed = float(struct.unpack('<f', "".join(map(chr, [int(arrBytes[4]), int(arrBytes[5]), int(arrBytes[6]), int(arrBytes[7])])))[0])
					# (m/s) meters at second

					# decide what to do...
					# strOutput = str(weight) + "kg " + str(position) + "m " + str(speed) + "m/s "
					# write_msg("%d:%s" % (messId, strOutput))
					objOutput = {"weight": weight, "position": position, "speed": speed, "timestamp": get_timestamp()}
					write_msg(json.dumps(objOutput))

		if messId == 31:
			# print messId
			start = arrMess[1].find("(")
			end = arrMess[1].find(")")
			bytesNum = arrMess[1][start + 1:end]
			# print bytesNum
			messBytes = arrMess[2][1:]
			if messBytes != lastMsg31:  # discard new message if is equal to last one
				lastMsg31 = messBytes
				arrBytes = messBytes.split()
				if bytesNum.isdigit():
					bytesNum = int(bytesNum)
				if bytesNum == len(arrBytes):
					axleX = int(arrBytes[0])
					# (%) percentage of X axle grade (frontal)
					axleY = int(arrBytes[1])
					# (%) percentage of Y axle grade (lateral)
					consumption = int(struct.unpack('<h', "".join(map(chr, [int(arrBytes[2]), int(arrBytes[3])])))[0])
					# (l/h) liters at hour
					lifting = get_lifting_status(int(arrBytes[4]))
					# lifting status (0='stop', 1='going up', 2='going down', 3='antenna down')
					translation = get_translation_status(int(arrBytes[5]))
					# translation status (0='stop', 1='going to load', 2='going to release')

					# decide what to do...
					# strOutput = str(axleX) + "% " + str(axleY) + "% " + str(consumption) + "l/h " + lifting + " " + translation
					# write_msg("%d:%s" % (messId, strOutput))
					objOutput = {"axleX": axleX, "axleY": axleY, "consumption": consumption, "lifting": lifting, "translation": translation, "timestamp": get_timestamp()}
					write_msg(json.dumps(objOutput))
					lastLifting = int(arrBytes[4])

		count += 1

		#every 0.5 sec see below (10 msg per second)
		if count % 5 == 0:
			try:
				if lastLifting == 3:
					subprocess.check_call("java -jar /root/slope-bananapro/TagsReader.jar " + str(antennaPower) + " "  + str(incremental), shell=True)
					lastLifting = 0
			except subprocess.CalledProcessError, e:
				write_log('Error executing lib TagsReader.jar: ' + str(e))

		#every 5 sec upload data and send watchdog
		if count == 50:
			count = 0
			pyCan.send(can_fd, 1, '60:' + flip)
			if flip == '0':
				flip = '1'
			if flip == '1':
				flip = '0'
			try:
				subprocess.check_call("python upload-data.py", shell=True)
			except subprocess.CalledProcessError, e:
				write_log('Error executing upload-data.py: ' + str(e))

		time.sleep(0.1)

except KeyboardInterrupt:
	write_log('Program exits with ctrl+c')

finally:
	pyCan.close(can_fd)
	write_log('/dev/can' + str(device) + ' closed in finally')

# print 'Wait ' + str(timeout) + ' sec for an message.....'
# print pyCan.read1(can_fd, timeout * 1000000)
# print 'Wait default timeout for an message.....'
# print pyCan.read1(can_fd)

# pyCan.close(can_fd)
# write_log('/dev/can' + str(device) + ' closed at the end')
# logFile.close()
# msgFile.close()
# exit()
<commit_msg>test pid<commit_after>#!/usr/bin/env python

# simple pyCan Example for can4linux
import time
import datetime
import signal
import sys
import subprocess
import struct
import json
import os

sys.path.insert(0, '/root/can4linux-code/can4linux-examples')
import pyCan

# the power expressed in (mW)
# default is around 660
# it must be an Integer greater then 45
# 45mW allows to detect tags at aroud 50cm distance
antennaPower = 2000

datafolder = '/root/slope-data/'
logFolder = '/root/slope-log/'

def get_incremental_number():
	maxcounter = 0
	listFiles = os.listdir(datafolder)
	for file in listFiles:
		if os.path.isfile(datafolder + file):
			name = file.split('_')
			if len(name) > 0:
				counter = name[0]
				if counter.isdigit():
					counter = int(counter)
					if counter > maxcounter:
				 		maxcounter = counter
	return maxcounter + 1

incremental = get_incremental_number()
msgFilePath = datafolder + str(incremental) + '_canbus-messages.txt'
logFilePath = logFolder + 'slope-canbus.log'

def get_lifting_status(status):
	if status == 0:
		return "stop"
	elif status == 1:
		return "going up"
	elif status == 2:
		return "going down"
	else:
		return "error"

def get_translation_status(status):
	if status == 0:
		return "stop"
	elif status == 1:
		return "going to load"
	elif status == 2:
		return "going to release"
	elif status == 3:
		return "antenna down"
	else:
		return "error"

def write_log(text):
	logfile = open(logFilePath, 'a', 1)
	now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
	logfile.write('[' + now + '] ' + text + '\n')
	logfile.close()

def write_msg(text):
	msgfile = open(msgFilePath, 'a+', 1)
	# now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
	msgfile.write(text + '\n')
	msgfile.close()

def get_timestamp():
	return str(int(round(time.time() * 1000)))

def sigterm_handler(_signo, _stack_frame):
	# Raises SystemExit(0):
	sys.exit(0)

signal.signal(signal.SIGTERM, sigterm_handler)

#print 'Python wrapper loaded'
#print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
write_log('Slope-Canbus Version 1.0')
write_log('Python wrapper loaded')
write_log('Incremental Log Number: ' + str(incremental))

# setting the device number
device = 0
defaultBaudrate = '250'

# open the can interface /dev/can0
try:
	fileBaud = open('/proc/sys/dev/Can/Baud', 'r+')
	baudRates = fileBaud.read().split()
	baudRates[device] = defaultBaudrate
	fileBaud.write(' '.join(baudRates))
	fileBaud.close()

except IOError:
	write_log('Could not set the new bitrate')
	exit()

except IndexError:
	write_log('No proper entry for bitrate of can' + str(device) + ' found')
	exit()

# print 'open can'+ str(device) + ' none blocking'
can_fd = pyCan.open(device)

if can_fd == -1:
	write_log('Error opening CAN device /dev/can' + str(device))
	exit()

try:
	write_log('Wait for message...')
	count = 0
	flip = '0'
	lastMsg30 = ""
	lastMsg31 = ""
	lastLifting = 0
	while True:
		data = pyCan.read(can_fd)
		arrMess = data.split(':', 3)
		messId = arrMess[0][:len(arrMess[0]) - 1]
		if messId.isdigit():
			messId = int(messId)
		if messId == 30:
			# print messId
			start = arrMess[1].find("(")
			end = arrMess[1].find(")")
			bytesNum = arrMess[1][start + 1:end]
			# print bytesNum
			messBytes = arrMess[2][1:]
			if messBytes != lastMsg30:  # discard new message if is equal to last one
				lastMsg30 = messBytes
				arrBytes = messBytes.split()
				if bytesNum.isdigit():
					bytesNum = int(bytesNum)
				if bytesNum == len(arrBytes):
					weight = int(struct.unpack('<h', "".join(map(chr, [int(arrBytes[0]), int(arrBytes[1])])))[0])
					# (kg) kilogrammes
					position = int(struct.unpack('<h', "".join(map(chr, [int(arrBytes[2]), int(arrBytes[3])])))[0])
					# (m) meters
					speed = float(struct.unpack('<f', "".join(map(chr, [int(arrBytes[4]), int(arrBytes[5]), int(arrBytes[6]), int(arrBytes[7])])))[0])
					# (m/s) meters at second

					# decide what to do...
					# strOutput = str(weight) + "kg " + str(position) + "m " + str(speed) + "m/s "
					# write_msg("%d:%s" % (messId, strOutput))
					objOutput = {"weight": weight, "position": position, "speed": speed, "timestamp": get_timestamp()}
					write_msg(json.dumps(objOutput))

		if messId == 31:
			# print messId
			start = arrMess[1].find("(")
			end = arrMess[1].find(")")
			bytesNum = arrMess[1][start + 1:end]
			# print bytesNum
			messBytes = arrMess[2][1:]
			if messBytes != lastMsg31:  # discard new message if is equal to last one
				lastMsg31 = messBytes
				arrBytes = messBytes.split()
				if bytesNum.isdigit():
					bytesNum = int(bytesNum)
				if bytesNum == len(arrBytes):
					axleX = int(arrBytes[0])
					# (%) percentage of X axle grade (frontal)
					axleY = int(arrBytes[1])
					# (%) percentage of Y axle grade (lateral)
					consumption = int(struct.unpack('<h', "".join(map(chr, [int(arrBytes[2]), int(arrBytes[3])])))[0])
					# (l/h) liters at hour
					lifting = get_lifting_status(int(arrBytes[4]))
					# lifting status (0='stop', 1='going up', 2='going down', 3='antenna down')
					translation = get_translation_status(int(arrBytes[5]))
					# translation status (0='stop', 1='going to load', 2='going to release')

					# decide what to do...
					# strOutput = str(axleX) + "% " + str(axleY) + "% " + str(consumption) + "l/h " + lifting + " " + translation
					# write_msg("%d:%s" % (messId, strOutput))
					objOutput = {"axleX": axleX, "axleY": axleY, "consumption": consumption, "lifting": lifting, "translation": translation, "timestamp": get_timestamp()}
					write_msg(json.dumps(objOutput))
					lastLifting = int(arrBytes[4])

		count += 1

		#every 0.5 sec see below (10 msg per second)
		if count % 5 == 0:
			try:
				if lastLifting == 3:
					subprocess.check_call("java -jar /root/slope-bananapro/TagsReader.jar " + str(antennaPower) + " "  + str(incremental), shell=True)
					lastLifting = 0
			except subprocess.CalledProcessError, e:
				write_log('Error executing lib TagsReader.jar: ' + str(e))

		#every 5 sec upload data and send watchdog
		if count == 50:
			count = 0
			pyCan.send(can_fd, 1, '60:' + flip)
			if flip == '0':
				flip = '1'
			if flip == '1':
				flip = '0'
			"""try:
				subprocess.check_call("python upload-data.py", shell=True)
			except subprocess.CalledProcessError, e:
				write_log('Error executing upload-data.py: ' + str(e))	"""

		time.sleep(0.1)

except KeyboardInterrupt:
	write_log('Program exits with ctrl+c')

finally:
	pyCan.close(can_fd)
	write_log('/dev/can' + str(device) + ' closed in finally')

# print 'Wait ' + str(timeout) + ' sec for an message.....'
# print pyCan.read1(can_fd, timeout * 1000000)
# print 'Wait default timeout for an message.....'
# print pyCan.read1(can_fd)

# pyCan.close(can_fd)
# write_log('/dev/can' + str(device) + ' closed at the end')
# logFile.close()
# msgFile.close()
# exit()
<|endoftext|>


<commit_before>import io
import itertools
import functools
import shlex
import sys
import threading
import traceback

from .exceptions import *

class Bot:
    def __init__(self, name):
        self.name = name
        self.storage = None
        self.backend = None
        self.plugins = []

    def set_storage(self, storage):
        self.storage = storage

    def set_backend(self, backend):
        self.backend = backend
        self.backend.add_event_listener("ready", self.on_ready)
        self.backend.add_event_listener("join", self.on_join)
        self.backend.add_event_listener("message", self.on_message)

    def add_plugin(self, plugin):
        self.plugins.append(plugin)
        plugin(self)

    def set_plugins(self, plugins):
        self.plugins.clear()
        for plugin in plugins:
            self.add_plugin(plugin)

    def run(self):
        self.backend.run(self.name)

    # event handlers
    def on_ready(self):
        for plugin in self.plugins:
            try:
                plugin.on_ready()
            except:
                traceback.print_exc()

    def on_join(self, msg):
        for plugin in self.plugins:
            try:
                plugin.on_join(msg)
            except:
                traceback.print_exc()

    def find_plugin(self, name):
        for plugin in self.plugins:
            if name in plugin.names:
                return plugin

    def call_plugins_on_message(self, msg):
        reply = functools.partial(self.send, msg["reply_to"])

        for plugin in self.plugins:
            try:
                plugin.on_message(msg, reply)
            except Exception as e:
                traceback.print_exc()
                reply(name + ": " + str(e))

    def call_plugins_on_respond(self, msg):
        reply = functools.partial(self.send, msg["reply_to"])

        for plugin in self.plugins:
            try:
                plugin.on_respond(msg, reply)
            except Exception as e:
                traceback.print_exc()
                reply(name + ": " + str(e))

    def call_plugins_on_command(self, msg):
        reply = functools.partial(self.send, msg["reply_to"])

        try:
            args = shlex.split(msg["message"])
        except ValueError:
            args = msg["message"].split(" ")  # try and cope with invalid data

        groups = itertools.groupby(args, lambda x: x == "|")
        commands = [list(group) for k, group in groups if not k]
        pipe_buffer = ""
        for command in commands:
            plugin = self.find_plugin(command[0])
            if not plugin:
                break

            try:
                stdin = io.StringIO(pipe_buffer)
                stdout = io.StringIO()
                msg["args"] = command
                msg["message"] = " ".join(command)
                plugin.on_command(msg, stdin, stdout, reply)
                pipe_buffer = stdout.getvalue()
            except StopCommand as e:
                self.send(msg["reply_to"], str(e))
                break
            except NotImplementedError:
                break
            except Exception as e:
                traceback.print_exc()
                self.send(msg["reply_to"], repr(e))
                break
        else:
            self.send(msg["reply_to"], pipe_buffer.strip())

    def on_message(self, msg):
        self.call_plugins_on_message(msg)

        reply = functools.partial(self.send, msg["reply_to"])

        m = msg["message"].strip()
        if m.startswith(self.name) or m.startswith("!"):
            if m.startswith("!"):
                m = m[1:].strip()
            else:
                m = m[len(self.name)+1:].strip()

            msg["message"] = m

            self.call_plugins_on_respond(msg)

            target = self.call_plugins_on_command
            threading.Thread(target=target, args=(msg,)).start()

    # actions
    def join(self, channel):
        self.backend.join(channel)

    def send(self, target, message):
        self.backend.send(target, str(message))

    def format(self, text, *properties):
        return self.backend.format(text, properties)
<commit_msg>Fix exception reporting<commit_after>import io
import itertools
import functools
import shlex
import sys
import threading
import traceback

from .exceptions import *

class Bot:
    def __init__(self, name):
        self.name = name
        self.storage = None
        self.backend = None
        self.plugins = []

    def set_storage(self, storage):
        self.storage = storage

    def set_backend(self, backend):
        self.backend = backend
        self.backend.add_event_listener("ready", self.on_ready)
        self.backend.add_event_listener("join", self.on_join)
        self.backend.add_event_listener("message", self.on_message)

    def add_plugin(self, plugin):
        self.plugins.append(plugin)
        plugin(self)

    def set_plugins(self, plugins):
        self.plugins.clear()
        for plugin in plugins:
            self.add_plugin(plugin)

    def run(self):
        self.backend.run(self.name)

    # event handlers
    def on_ready(self):
        for plugin in self.plugins:
            try:
                plugin.on_ready()
            except:
                traceback.print_exc()

    def on_join(self, msg):
        for plugin in self.plugins:
            try:
                plugin.on_join(msg)
            except:
                traceback.print_exc()

    def find_plugin(self, name):
        for plugin in self.plugins:
            if name in plugin.names:
                return plugin

    def call_plugins_on_message(self, msg):
        reply = functools.partial(self.send, msg["reply_to"])

        for plugin in self.plugins:
            try:
                plugin.on_message(msg, reply)
            except Exception as e:
                traceback.print_exc()
                reply(str(e))

    def call_plugins_on_respond(self, msg):
        reply = functools.partial(self.send, msg["reply_to"])

        for plugin in self.plugins:
            try:
                plugin.on_respond(msg, reply)
            except Exception as e:
                traceback.print_exc()
                reply(name + ": " + str(e))

    def call_plugins_on_command(self, msg):
        reply = functools.partial(self.send, msg["reply_to"])

        try:
            args = shlex.split(msg["message"])
        except ValueError:
            args = msg["message"].split(" ")  # try and cope with invalid data

        groups = itertools.groupby(args, lambda x: x == "|")
        commands = [list(group) for k, group in groups if not k]
        pipe_buffer = ""
        for command in commands:
            plugin = self.find_plugin(command[0])
            if not plugin:
                break

            try:
                stdin = io.StringIO(pipe_buffer)
                stdout = io.StringIO()
                msg["args"] = command
                msg["message"] = " ".join(command)
                plugin.on_command(msg, stdin, stdout, reply)
                pipe_buffer = stdout.getvalue()
            except StopCommand as e:
                self.send(msg["reply_to"], str(e))
                break
            except NotImplementedError:
                break
            except Exception as e:
                traceback.print_exc()
                self.send(msg["reply_to"], repr(e))
                break
        else:
            self.send(msg["reply_to"], pipe_buffer.strip())

    def on_message(self, msg):
        self.call_plugins_on_message(msg)

        reply = functools.partial(self.send, msg["reply_to"])

        m = msg["message"].strip()
        if m.startswith(self.name) or m.startswith("!"):
            if m.startswith("!"):
                m = m[1:].strip()
            else:
                m = m[len(self.name)+1:].strip()

            msg["message"] = m

            self.call_plugins_on_respond(msg)

            target = self.call_plugins_on_command
            threading.Thread(target=target, args=(msg,)).start()

    # actions
    def join(self, channel):
        self.backend.join(channel)

    def send(self, target, message):
        self.backend.send(target, str(message))

    def format(self, text, *properties):
        return self.backend.format(text, properties)
<|endoftext|>