def func_wrapper(*args, **kwargs):
   if settings.TEST or settings.SHELL:
     # Tests and the shell should just run immediately and not catch any
     # errors.
     return func(*args, **kwargs)
   elif settings.DEBUG or settings.BACKGROUND:
     command_name = func.__name__
     command_run = LoggedCommand.objects.create(
         command_name=command_name, started=now())
     results = None
     try:
       results = func(*args, **kwargs)
       command_run.completed = now()
     except Exception:
       exc_info = sys.exc_info()
       command_run.error = log_error(
           '{} error'.format(command_name), exc_info=exc_info)
       if settings.DEBUG:
         type_, value_, traceback_ = exc_info
         print(value_.__repr__())
         print('\n'.join(traceback.format_tb(traceback_)))
     command_run.save()
     return results
   else:
     # Otherwise we're on web or something and we wanna kick this function
     # off to a background thread.
     q.enqueue(func, *args, **kwargs)
Beispiel #2
0
 def logged_existing_error(self, title):
     existing = self.filter(title=title,
                            created__gte=now() - timedelta(days=1),
                            fixed__isnull=True).first()
     if existing:
         existing.count += 1
         existing.latest = now()
         existing.save()
         if settings.DEBUG:
             print('Incrementing "{}" error count'.format(title))
         return existing
Beispiel #3
0
def use_token_and_return_user(token_str, nnow=None):
    if not token_str:
        return
    if isinstance(token_str, LoginToken):
        raise Exception(
            'You are supposed to hand the token string to this function, not the '
            'token object')
    nnow = nnow or now()
    existing = LoginToken.objects.filter(token=token_str,
                                         used__isnull=True).first()
    if existing:
        existing.used = nnow
        existing.save()
        if existing.user:
            return existing.user
        elif existing.email:
            # This just makes sign up links work as log in links, which is especially
            # handy for developing the web demo.
            existing_user = User.objects.filter(email=existing.email).first()
            if existing_user:
                return existing_user
            return User.objects.create(email=existing.email,
                                       username=existing.email)
        raise Exception('LoginToken {} has neither user nor email'.format(
            existing.pk))
Beispiel #4
0
 def as_html(self, nnow=None):
     nnow = nnow or now()
     today = nnow.date()
     days = []
     day_delta_and_css_classes = [(-2, 'two_before'), (-1, 'one_before'),
                                  (0, ''), (1, 'one_after'),
                                  (2, 'two_after')]
     for day_delta, css_class in day_delta_and_css_classes:
         this_day = self.on_day + timedelta(days=day_delta)
         if self.min_day and this_day < self.min_day:
             continue
         if self.max_day and this_day > self.max_day:
             continue
         is_current = this_day == self.on_day
         text = days_ago_str(this_day)
         if this_day == today:
             url = reverse('enter_time')
         else:
             url = url_with_date(reverse('enter_time'), day=this_day)
         days.append(
             RollerDay(is_current, text, css_class, url,
                       date_to_url_str(this_day)))
     try:
         return render_to_string('date_roller.html', {'days': days})
     except TemplateDoesNotExist:
         raise Exception(
             'In order to use the date roller you need to add djaveNav/templates '
             'to the DIRS attribute in the TEMPLATES setting')
Beispiel #5
0
 def log_long_request(self, path, duration, method, variables, nnow=None):
     nnow = nnow or now()
     existing = self.filter(path=path,
                            method=method,
                            created__gte=now() - timedelta(days=1)).first()
     if existing:
         existing.total_duration += duration
         existing.latest = now()
         existing.count += 1
         existing.save()
         return existing
     return self.create(path=path,
                        total_duration=duration,
                        method=method,
                        variables=variables,
                        latest=now(),
                        count=1)
Beispiel #6
0
def ajax_delete(request):
  instance = get_request_ajax_obj(request)

  if hasattr(instance, 'deleted'):
    instance.deleted = now()
    instance.save()
  else:
    instance.delete()
Beispiel #7
0
 def send(self, _post=None, nnow=None):
     _post = _post or post
     nnow = nnow or now()
     if _post(self.webhook_url, json.loads(self.payload)):
         self.success_at = nnow
     self.last_send_attempt_at = nnow
     self.attempts += 1
     self.save()
Beispiel #8
0
 def __init__(self, request_get, nnow=None):
   nnow = nnow or now()
   default_to_date = nnow.date()
   self.status_filter = get_fixable_status_filter()
   filters = [self.status_filter]
   super().__init__(
       default_from_date(nnow=nnow), default_to_date, request_get=request_get,
       filters=filters)
   self.set_contents(self.get_table())
Beispiel #9
0
def resize_all(nnow=None, **kwargs):
    """ If all we ever get is a SignedFile, then the image will never be
  resized. """
    nnow = nnow or now()
    photos = Photo.objects.filter(
        ~Q(file_name=''),  # Sometimes a single empty file name is in the db
        resized_at__isnull=True,
        created__gte=nnow - timedelta(days=7))
    for photo in photos:
        photo.as_child_class().resize(**kwargs)
Beispiel #10
0
 def notify(self, to_emails, title, message, email_sender=None):
   """ Log to_emails, title, and message. If it's the first we've seen it
   today, send an email as well. """
   email_sender = email_sender or StaffEmailSender()
   if isinstance(to_emails, str):
     to_emails = [to_emails]
   # I had days=1, but what if you want to send a daily notification? Monday
   # it goes out at 3:01am, Tuesday it tries to go out at 3:00am but it
   # doesn't because it went out within the last day.
   existing = self.filter(
       to=str(to_emails), title=title, message=message,
       created__gte=now() - timedelta(hours=23)).first()
   if existing:
     existing.count += 1
     existing.latest = now()
     existing.save()
   else:
     self.create(
         to=str(to_emails), title=title, message=message, count=1,
         latest=now())
     email_sender.send_mail(
         title, message, settings.SERVER_EMAIL, to_emails)
Beispiel #11
0
def _date_or_date_time(field, raw_value):
    if raw_value:
        if field.type == DATE:
            value = parse_date(raw_value)
            example = date.today().isoformat()
        elif field.type == DATE_TIME:
            value = parse_datetime(raw_value)
            example = now().isoformat()
        else:
            raise Exception(field.type)
        if not value:
            raise Problem(
                ('{} is not a valid {}. I am looking for something more '
                 'like {}').format(raw_value, field.type, example))
        return value
Beispiel #12
0
def get_fixables(model,
                 from_date=USE_DEFAULT,
                 to_date=USE_DEFAULT,
                 status=USE_DEFAULT,
                 nnow=None):
    """ Assumes you have a created column and a fixed column. Easiest thing is to
  inherit from djavError.models.fixable I'm leaving this here instead of in
  djavError.models.fixable because this function knows about UI specific
  filters and defaults. """
    nnow = nnow or now()
    if from_date == USE_DEFAULT:
        from_date = default_from_date(nnow=nnow)
    if to_date == USE_DEFAULT:
        to_date = nnow.date()
    query_set = model.objects.filter(
        created__gte=beginning_of_day(from_date),
        created__lte=end_of_day(to_date)).order_by('-created')
    return do_fixed_filter(query_set, status)
Beispiel #13
0
def _js_variables_to_py(model, request_post):
  field_defs = model_fields_lookup(model)
  to_return = {}
  for key in request_post:
    if key not in ['pk', 'type', 'csrfmiddlewaretoken']:
      field = field_defs.get(key, None)
      if not field:
        raise Problem('{} is not a field in {}'.format(
            key, model.__class__.__name__))
      DATE_TIME
      if field.type == BOOLEAN and request_post[key] in [
          'true', 'false', 'True', 'False']:
        to_return[key] = request_post[key].lower() == 'true'
      elif field.type == DATE_TIME and request_post[key] in [
          'now', 'Now']:
        to_return[key] = now().isoformat()
      else:
        to_return[key] = request_post[key]
  return to_return
Beispiel #14
0
def clean_up_never_used(nnow=None, bucket=None):
    """ I find out about every file that users upload because the server has to
  sign them. But WHY they're being used doesn't become clear until somebody
  creates a File object, and then the child class explains everything. So
  whatever SignedFiles exist without File objects are files that got uploaded,
  but we never found out why. So just delete them. This is quite common. People
  might change their minds and upload a different file, or they may just never
  submit the form that says why they uploaded that file.

  Once we know whether or not a file is used, we no longer need the
  SignedFile. """
    nnow = nnow or now()
    # It may take a moment for the background thread to catch up and use a file,
    # or it may take the user a while to submit the form that says how to use the
    # file they just uploaded. So give it a day for the reason for the upload to
    # show up, and if it doesn't, chuck the upload.
    for signed in SignedFile.objects.filter(created__lte=nnow -
                                            timedelta(days=1)).order_by('pk'):
        if not signed_file_is_used(signed):
            signed.delete_file(bucket=bucket)
        signed.delete()
Beispiel #15
0
    def create_error(self,
                     title,
                     message,
                     exc_info=None,
                     extra_to=None,
                     supress_stack_trace=False):
        # Just in case somebody passes a tuple in or whatever as the message.
        message = str(message)

        value_ = None
        traceback_ = None
        if exc_info:
            type_, value_, traceback_ = exc_info
        stack_trace = ''
        if supress_stack_trace:
            stack_trace = ''
        elif traceback_:
            stack_trace = '\n'.join(traceback.format_tb(traceback_))
        else:
            stack_trace = '\n'.join(
                [line.strip() for line in traceback.format_stack()])

        error_message = ''
        if value_:
            error_message = value_.__repr__()

        to_emails = [settings.EMAIL_ERRORS_TO]
        if extra_to:
            to_emails.extend(extra_to)

        return self.create(title=title,
                           count=1,
                           latest=now(),
                           message=message,
                           error_message=error_message,
                           stack_trace=stack_trace,
                           to=','.join(to_emails))
Beispiel #16
0
def clean_up_no_longer_needed(nnow=None, bucket=None):
    """ Files have to describe when they can be thrown out. bucket is just used
  in tests to inject dependencies, but in case anybody actually tries to just
  clean_up_no_longer_needed in a specific bucket, I only deal with files in
  bucket if provided. """
    nnow = nnow or now()
    # Sometimes a single empty file name slips into the database. There's a
    # unique constraint, so only 1 empty file_name is allowed haha Anyway
    # obviously you can't delete a file with no name.
    for file in File.objects.filter(~Q(file_name=''), keep_until__lt=nnow):
        file = file.as_child_class()
        if bucket and bucket.name() != file.bucket_config().name:
            continue
        if file.explain_why_can_delete():
            file.delete(bucket=bucket)
        else:
            file.calc_and_set_keep(nnow=nnow)
            if file.keep_until >= nnow:
                file.save()
            else:
                raise Exception(
                    'Theres no reason to keep {} but calc_and_set_keep set '
                    'keep_until to {} which is in the past'.format(
                        file, file.keep_until))
Beispiel #17
0
 def save(self, *args, **kwargs):
     if not self.latest:
         self.latest = now()
     super().save(*args, **kwargs)
Beispiel #18
0
 def increment(self):
     self.count += 1
     self.latest = now()
     self.save()
Beispiel #19
0
    def resize(self,
               verbose=False,
               image_opener=None,
               use_os=None,
               use_open=None,
               **kwargs):
        """ This is a whole thing, and should run only in the background. It tries
    to run right away, but it also runs every night at midnight to help catch
    problems, so there are races possible, such as both threads trying to
    delete the working images. """
        if self.resized_at:
            return True

        image_opener = image_opener or Image.open
        use_os = use_os or os
        use_open = use_open or open
        bucket = kwargs.get('bucket', None) or self._bucket()

        if self.__class__ in (File, Photo):
            raise Exception('Call resize on the child class')
        if self.resized_at:
            return
        if not self.file_name:
            raise Exception('This photo was deleted and can\'t be recovered.')
        bucket.download(self.file_name)

        try:
            image = image_opener(self.file_name)
        except OSError as ex:
            if ex.args[0].find('cannot identify image file') == 0:
                self.notify_bad_image(**kwargs)
                return False
            raise ex

        # Sometimes people will upload pngs. Sometimes they'll upload pngs but
        # replace the file extension with jpg. Whatever, people are dumb at image
        # file formats. In any case just make sure it doesn't have an alpha channel
        # so we can save it as a jpg, which is pretty much the sane format for a
        # photograph.
        try:
            image = image.convert('RGB')
        except OSError as ex:
            if ex.args[0].find('image file is truncated') == 0:
                self.notify_bad_image(**kwargs)
                return False
            raise ex

        (width, height) = (image.width, image.height)
        max_dimension = max((width, height))
        if max_dimension > self.max_width_or_height():
            ratio = self.max_width_or_height() / max_dimension
            image = image.resize((int(ratio * width), int(ratio * height)))

        if use_os.path.exists(self.file_name):
            use_os.remove(self.file_name)

        # I don't use the handy `with ... as` because I didn't bother to figure out
        # how to mock that whole thing in tests.
        file_handle = use_open(self.file_name, 'wb')
        image.save(file_handle, format='JPEG', quality=100)
        file_handle.close()

        self.do_additional_resize_steps(self.file_name, self.file_name,
                                        **kwargs)

        bucket.upload(self.file_name)
        use_os.remove(self.file_name)

        self.resized_at = kwargs.get('nnow', now())
        self.save()

        self.post_resize()
        return True
Beispiel #20
0
def all_fixed(request, model_name, pks):
  model = model_from_name(model_name, subclass_of=Fixable)
  pks = [int(id) for id in pks.split(',')]
  model.allowed_by_user(request.user).filter(pk__in=pks).update(fixed=now())
Beispiel #21
0
 def mark_deleted(self, nnow=None):
     nnow = nnow or now()
     self.deleted = nnow
     self.save()
Beispiel #22
0
def set_fixable_stuff(fixable, **kwargs):
    fixable.count = kwargs.get('count', 1)
    fixable.latest = kwargs.get('latest', now())
    fixable.fixed = kwargs.get('fixed', None)
    fixable.save()
    return fixable
Beispiel #23
0
def default_from_date(nnow=None):
    nnow = nnow or now()
    return nnow.date() - timedelta(days=7)