class WaitingNumberBatch(models.Model): choices_src = list( zip(USER_TO_NAMES.keys(), [i.get('placement', '?') for i in USER_TO_NAMES.values()])) src = models.CharField(choices=choices_src, db_index=True, max_length=50) src_ip = models.GenericIPAddressField() date = models.DateTimeField(db_index=True, default=timezone.now) date_delta = models.IntegerField(null=True) proc_delay = models.FloatField(null=True) numbers = models.ManyToManyField(WaitingNumber) class Meta: ordering = ['-date', 'src'] def __unicode__(self): return '{} | {}'.format(self.src, str(self.date)) def serialize_numbers(self, verbose=False): return [num.serialize(verbose) for num in self.numbers.all()] def serialize(self, verbose=False): return { 'src': self.src, 'date': self.date.strftime('%s'), 'src_ip': self.src_ip, 'numbers': [num.serialize(verbose) for num in self.numbers.all()], 'proc_delay': self.proc_delay, 'date_delta': self.date_delta, 'placement': USER_TO_NAMES.get(self.src, {}).get('placement') }
def get_current_numbers(src=None): sources = [src] if src in USER_TO_NAMES.keys() else USER_TO_NAMES.keys() data = [] for k in sources: try: newest = NewestNumberBatch.objects.get(src=k) data.append(newest.serialize(verbose=True)) except ObjectDoesNotExist: logging.warning( 'Warning! Database for the Display above Room {} is empty!'. format(k)) return data
def get_config(request): if not request.POST or 'user' not in request.POST or 'password' not in request.POST: logger.info("Received an invalid config request {} from {}".format(request.POST, request.META.get('HTTP_X_FORWARDED_FOR'))) return HttpResponse(status=401, content='POST request incomplete!\n') user = request.POST.get('user') if user not in USER_TO_NAMES.keys() or RECOGNIZER_AUTH != request.POST.get('password'): logger.info("Received an unauthorized config request {} from {}".format(request.POST, request.META.get('HTTP_X_FORWARDED_FOR'))) return HttpResponse(status=401, content="permission denied!\n") config = RECOGNIZER_CONFIG.get(user) num_batches_newest = NewestNumberBatch.objects.filter(src=user) if num_batches_newest.exists(): config['current_numbers'] = num_batches_newest.latest('date').newest.serialize_numbers() else: num_batches = WaitingNumberBatch.objects.filter(src=user) if num_batches.exists(): config['current_numbers'] = num_batches.latest('date').serialize_numbers() template_path = os.path.join(RECOGNITION_TEMPLATES_PATH, 'template_{}.png'.format(user)) if os.path.exists(template_path): with open(template_path, 'rb') as f: config['template'] = b64encode(f.read()).decode('utf-8') digit_mask_path = os.path.join(RECOGNITION_TEMPLATES_PATH, 'digit_mask.png') if os.path.exists(digit_mask_path): with open(digit_mask_path, 'rb') as f: config['digit_mask'] = b64encode(f.read()).decode('utf-8') return JsonResponse(config, safe=False)
def serialize(self, verbose=False): return { 'src': self.src, 'date': self.date.strftime('%s'), 'src_ip': self.src_ip, 'numbers': [num.serialize(verbose) for num in self.numbers.all()], 'proc_delay': self.proc_delay, 'date_delta': self.date_delta, 'placement': USER_TO_NAMES.get(self.src, {}).get('placement') }
def api(request, pa=None): src = [pa] if pa else USER_TO_NAMES.keys() result = {'entries': [], 'errors': [], 'openings': OPENINGS} for s in src: try: newest = NewestNumberBatch.objects.get(src=s) result['entries'].append(newest.newest.serialize()) except (MultipleObjectsReturned, ObjectDoesNotExist): result['errors'].append("Pruefungsamt '{}' not found!".format(s)) return HttpResponse(json.dumps(result), content_type='application/json; charset=utf8')
class NewestNumberBatch(models.Model): # To minimze database queries, the newest Batch gets stored seperately and # only contains the newest WaitingNumberBatch choices_src = list( zip(USER_TO_NAMES.keys(), [i.get('placement', '?') for i in USER_TO_NAMES.values()])) src = models.CharField(choices=choices_src, max_length=50) date = models.DateTimeField() newest = models.ForeignKey(WaitingNumberBatch, on_delete=None) def __unicode__(self): return '{} | {}'.format(self.src, str(self.newest)) def serialize(self, verbose=False): serialized = { 'newest': self.newest.serialize(verbose), 'date': self.date.strftime('%s') } if verbose: updated = (timezone.now() - self.date).seconds serialized['updated'] = "" if updated < 10 else _( "Warning! Last check {} ago".format( timesincesecondsonly(self.date))) return serialized
def check_notify(request): down = [] for k in USER_TO_NAMES.keys(): try: newest = NewestNumberBatch.objects.get(src=k) except (ObjectDoesNotExist, MultipleObjectsReturned): continue offline_m = (timezone.now() - newest.date).seconds / 60 if offline_m > 5: status = '{0} down for {1} minutes'.format(k, int(offline_m)) down.append(status) if (offline_m < 60 or not offline_m % 10) and offline_m < 600: logger_req.fatal(status) return HttpResponse( status=200, content='Everything\'s fine' if not down else '\n'.join(down))
def api2(request, paT=None, ops=None, pa=None): entries = [] pa_rooms = [paT] if paT else USER_TO_NAMES.keys() for pa_room in pa_rooms: try: newest = NewestNumberBatch.objects.get( src=pa_room) # get newest WaitingNumberBatch via newest-table except (MultipleObjectsReturned, ObjectDoesNotExist): # dict['errors'].append("Table '%s' not found!" % pa_room) continue num = newest.newest nums = num.numbers.all() nums = nums.filter(src='H ' + pa) if pa else nums if not nums: # dict['errors'].append("Pruefungsamt '%s' not found!" % pa) continue ticket_place = { "type": "Place", "uid": _md5.md5(str(pa_room)).hexdigest(), "subType": "Prüfungsamt", "name": pa_room, "alternateName": ["H {0}".format(pa_room)], "url": "http://www.pruefungen.tu-berlin.de/", "description": "Prüfungsamt der TU Berlin, Raum {0}".format(pa_room), "image": "http://www.tu-berlin.de/fileadmin/Aperto_design/img/logo_01.gif", "video": "https://www.youtube.com/watch?v=BROWqjuTM0g", "address": { "addressCountry": "Germany", "addressLocality": "Berlin", "addressRegion": "Berlin", "postOfficeBoxNumber": "", "postalCode": "10623", "streetAddress": "Straße des 17. Juni 135" }, "openingHours": [{ 'opens': ':'.join([str(op['begin'])[:-2], str(op['begin'])[-2:]]), 'closes': ':'.join([str(op['end'])[:-2], str(op['end'])[-2:]]), 'validFrom': timezone.datetime(1970, 1, 1).ctime(), 'validThrough': timezone.datetime(2030, 1, 1).ctime(), 'dayOfWeek': timezone.datetime(1970, 1, 4 + op['weekday']).strftime('%A') } for op in OPENINGS if op.has_key('begin')], "geo": { "type": "GeoShape", "uid": "74398574398768945874", "polygon": [ "12.323590,53.518139,0.000000", "13.324133,53.518108,1.000000", "14.323690,-53.518250,2.000000", "15.323590,-53.518139,3.000000" ] } } for src_counter in nums: try: avg = StatisticalData.objects.get( src=src_counter.src).avg_whole except (MultipleObjectsReturned, ObjectDoesNotExist): # dict['errors'].append("Statistical Data for {0} not availible!".format(src_counter.src)) avg = 0 ticket = { 'type': "Ticket", 'uid': _md5.md5(str(src_counter.pk)).hexdigest(), 'currentTicketNumber': src_counter.number, 'approxwaittime': (timezone.now() + timezone.timedelta(0, int(avg))).ctime(), 'date': src_counter.date.ctime(), 'room': src_counter.src, 'servicetype': { "name": "Prüfungsamt" }, 'counter': src_counter.pk, } ticket_place_copy = copy.deepcopy(ticket_place) ticket['place'] = ticket_place_copy entries.append(ticket) resp = HttpResponse(json.dumps(entries), content_type='application/json; charset=utf8') resp['Access-Control-Allow-Origin'] = '*' return resp
def write(request): if not request.POST or not {'user', 'password', 'ts', 'numbers', 'begin'}.issubset(request.POST): logger.info("received an invalid write request: %s" % request) return HttpResponse(status=401, content='POST request incomplete!\n') if request.POST.get('user') not in USER_TO_NAMES.keys() or \ RECOGNIZER_AUTH != request.POST.get('password'): logger.info("received an unauthorized write request: %s" % request) return HttpResponse(status=401, content="permission denied!\n") #---------------------- validating input --------------------- numbers = [] for number in request.POST.get('numbers', '').strip().split(' '): if number.isdigit(): numbers.append(int(number)) else: numbers.append(-1) try: ts = int(request.POST.get('ts', 0)) begin_ts = float(request.POST.get('begin', 0.0)) except ValueError: ts = 0 begin_ts = 0.0 src = request.POST.get('user') displays = USER_TO_NAMES.get(src, {}).get('displays', []) logging.warning(src) logging.warning(ts) logging.warning(begin_ts) logging.warning(len(numbers)) logging.warning(len(displays)) if not src or not ts or not begin_ts \ or len(numbers) != len(displays): return HttpResponse(status=400, content='did not validate!\n') request_ip = request.META.get('HTTP_X_FORWARDED_FOR', '') if not request_ip: request_ip = request.META.get('REMOTE_ADDR', '') # get todays opening times for validation date_ = timezone.datetime.fromtimestamp(ts, tz=pytz.timezone(TIME_ZONE)) for i_ in OPENINGS: if date_.isoweekday() == i_['weekday']: opening_time = i_ break else: opening_time = None num_batch_newest, old_num_batch = _get_old_batches(src) old_numbers = list(old_num_batch.numbers.all()) if old_num_batch else [] new_batch = None for num, _src in zip(numbers, displays): if _src == "H 25": num += 1000 # H25 hat ne angetapte 1 vorne dran old_num_obj = None if old_num_batch is not None: old_number_ = [i for i in old_numbers if i.src == _src] if old_number_: old_num_obj = old_number_[0] if old_num_obj.number == num or num == -1: # if number stays or comes outside of the opening times, just update continue # if not opening_time or 'begin' not in opening_time or \ # opening_time['begin'] > int(date_.strftime('%H%M')) or \ # opening_time['end'] < int(date_.strftime('%H%M'))-60: #60min buffer # continue # compute delta, if not first DB-Entry new_number_date_delta = (date_ - old_num_obj.date).seconds if old_num_obj else -1 src_statistic = statistics_handling.get_src_statistic(_src) if src_statistic is None: src_statistic = statistics_handling.create_statistic(_src, date_) new_num_obj = WaitingNumber(number=num, src=_src, date=date_, date_delta=new_number_date_delta, proc_delay=time.time() - begin_ts, statistic=src_statistic) new_num_obj.save() if not new_batch: # proc_delay will be set after EVERYTHING else new_batch = WaitingNumberBatch(src=src, src_ip=request_ip, date=date_, proc_delay=None, date_delta=(date_-old_num_batch.date).seconds if old_num_batch else -1) new_batch.save() [new_batch.numbers.add(i) for i in old_numbers] [new_batch.numbers.remove(i) for i in old_numbers if i.src == _src] new_batch.numbers.add(new_num_obj) if new_number_date_delta < (opening_time.get('end', 0)-opening_time.get('begin', 0))*60: # Update Stats if num is not first of the day, e.g. date_delta < openings statistics_handling.update_statistic(_src, new_number_date_delta, new_batch, date_) for subscriber in Subscriber.objects.filter(src=_src, protocol='sms'): subscriber.handle(num) if num_batch_newest is None: num_batch_newest = NewestNumberBatch(src=src, newest=old_num_batch) if new_batch: new_batch.proc_delay = time.time() - begin_ts new_batch.save() # replace NewestNumberBatch num_batch_newest.newest = new_batch num_batch_newest.date = date_ num_batch_newest.save() if request.FILES: _save_images(request, displays) return HttpResponse(status=201)
from django.db import models from django.utils.translation import ugettext as _ from django.utils import timezone from pa3.settings import USER_TO_NAMES from pa3_web.templatetags.pa3_timesinceseconds import timesincesecondsonly, timesinceseconds all_displays = [] [all_displays.extend(i.get('displays', [])) for i in USER_TO_NAMES.values()] choices_displays = zip(all_displays, all_displays) class StatisticalData(models.Model): # Stores statistical information on the numbers, to minimize the # computation effort src = models.CharField(max_length=50, choices=choices_displays) date = models.DateTimeField(default=timezone.now) # for sorting purposes avg = models.FloatField(default=0.0) # current Average avg_len = models.IntegerField( default=-1) # Length over which the avg is computed (count()) avg_sum = models.IntegerField( default=0) # Sum from which the avg is computed (avg=sum/len) avg_proc_delay_sum = models.IntegerField( default=0 ) # Sum from which the avg_proc_delay is computed (avg=sum/len) avg_proc_delay_len = models.IntegerField( default=-1 ) # Len from which the avg_proc_delay is computed (avg=sum/len)