Skip to content
Snippets Groups Projects
Select Git revision
  • c1b26acae295034e7aab2414ba50047cc889cafe
  • master default protected
  • android-7.1.2_r28_klist
  • oreo-mr1-iot-release
  • sdk-release
  • pie-cts-dev
  • pie-cts-release
  • pie-vts-release
  • nougat-iot-release
  • pie-gsi
  • pie-platform-release
  • pie-r2-release
  • pie-r2-s1-release
  • pie-release
  • pie-dev
  • oreo-m4-s4-release
  • o-mr1-iot-preview-8
  • oreo-m2-s2-release
  • oreo-m2-s1-release
  • oreo-m6-s2-release
  • oreo-m6-s3-release
  • android-o-mr1-iot-release-1.0.4
  • android-9.0.0_r8
  • android-9.0.0_r7
  • android-9.0.0_r6
  • android-9.0.0_r5
  • android-8.1.0_r46
  • android-8.1.0_r45
  • android-n-iot-release-smart-display-r2
  • android-vts-8.1_r5
  • android-cts-8.1_r8
  • android-cts-8.0_r12
  • android-cts-7.1_r20
  • android-cts-7.0_r24
  • android-cts-6.0_r31
  • android-o-mr1-iot-release-1.0.3
  • android-cts-9.0_r1
  • android-8.1.0_r43
  • android-8.1.0_r42
  • android-n-iot-release-smart-display
  • android-p-preview-5
41 results

metrics_client.cc

Blame
  • views.py 15.03 KiB
    import collections
    import datetime
    import json
    import os
    import socket
    import re
    import hashlib
    
    from django.conf import settings
    from django.db.models import Q
    from django.core.cache import cache
    from django.core.exceptions import ObjectDoesNotExist
    from django.core.exceptions import SuspiciousOperation
    from django.db import transaction
    from django.http import HttpResponse, HttpResponseNotAllowed, JsonResponse
    from django.http import QueryDict
    from django.shortcuts import redirect, render, get_object_or_404
    from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
    from django.views.generic import TemplateView
    
    from .models import Host, Exercise, Request, Room, ExerciseOption
    from user.models import Profile
    
    
    def load_secret():
        '''
        Communication between hosts and server is protected by a secret to prevent
        malicious users from injecting invalid status updates.
        '''
        secret = cache.get('secret_hosts')
        if secret is None:
            with open(os.path.join(settings.BASE_DIR, 'secret_hosts'), 'r') as f:
                secret = f.read().strip()
            cache.set('secret_hosts', secret)
        return secret
    
    
    def remote_cip_hostname(request):
        # "faui00x" in "faui00x.cs.fau.de".
        try:
            hostname = socket.gethostbyaddr(
                request.META['REMOTE_ADDR'])[0].split('.')[0]
            return re.sub('-win$', '', hostname) #drop -win from windows cip hosts
        except (socket.gaierror, socket.herror):
            return ""
    
    
    def _get_rooms(public=True):
        if public:
            rooms = Room.objects.filter(order__gte=0)
        else:
            rooms = Room.objects.all()
        return rooms
    
    
    @ensure_csrf_cookie
    def index(request, room):
        room_filtered = Room.objects.filter(name=room)
        if len(room_filtered) == 1:
            room = room_filtered[0]
        else:
            return redirect('index')
        return render(request, 'server/index.html', {'room': room, 'rooms': _get_rooms()})
    
    
    @ensure_csrf_cookie
    def optin(request):
        return render(request, 'server/optin.html', {'rooms': _get_rooms()})
    
    
    def faq(request):
        return render(request, 'server/faq.html', {'rooms': _get_rooms()})
    
    
    def privacypolicy(request):
        return render(request, 'server/privacypolicy.html', {'rooms': _get_rooms()})
    
    
    def legalnotice(request):
        return render(request, 'server/legalnotice.html', {'rooms': _get_rooms()})
    
    
    def cipmap_beamer_user(request):
        response = redirect('index-room', room='cip2')
        response.set_cookie(key='cipmap-beamer-user', value=True, secure=True)
        return response
    
    
    # Disable CSRF-checks to allow automated POST requests to update the state.
    @csrf_exempt
    def hosts(request):
        if request.method == 'GET':
    
            hostname = remote_cip_hostname(request)
    
            result = {
                'hostname': hostname,
            }
    
            for host in Host.objects.all():
                result[host.host_name] = {
                    'name': host.user_name,
                    'gecos': host.user_gecos,
                    'idle': host.user_idle,
                    'occupied': host.occupied,
                    'update': int(host.last_update.timestamp()),
                }
    
            result['exercises_today'] = _get_lectures_today()
            result['temperatures'] = _get_temperatures()
    
            indent = None
            if settings.DEBUG:
                indent = 4
    
            return JsonResponse(result, json_dumps_params={'indent': indent})
    
        elif request.method == 'POST':
            try:
                name = request.POST['name']
                gecos = request.POST['gecos']
                idle = request.POST['idle']
                occupied = request.POST['occupied'].lower() == "true"
                secret = request.POST['secret']
            except KeyError:
                raise SuspiciousOperation('missing fields')
            # Some hosts are behind NAT and use this header.
            hostname = None
            try:
                hostname = request.POST['host']
            except KeyError:
                pass
    
            if secret != load_secret():
                raise SuspiciousOperation('invalid secret')
    
            if hostname is None:
                hostname = remote_cip_hostname(request)
    
            with transaction.atomic():
                host = Host.objects.get_or_create(host_name=hostname,
                        defaults={'occupied': occupied, 'user_name': "", 'user_gecos': ""})[0]
    
                # User no longer logged in, delete all requests for this host.
                # This breaks if someone logs out and someone else logs in faster than we get
                # the update, but we can't don anything against it.
                if not occupied and host.occupied != occupied:
                    Request.objects.filter(host=hostname).delete()
    
                host.user_name = name
                host.user_gecos = gecos
                host.user_idle = idle
                host.occupied = occupied
    
                host.save()
    
            return HttpResponse()
    
        else:
            return HttpResponseNotAllowed(['GET', 'POST'])
    
    
    def __hash_username(username):
        return hashlib.sha512((username + username).encode()).hexdigest()
    
    
    def __request_type_to_field(request_type_text):
        # It's okay (and wanted!) that it raises a KeyError on invalid inputs
        text_to_num = {v: k for k, v in Request.REQUEST_CHOICES}
        return text_to_num[request_type_text]
    
    
    def __check_allowance_of_requesttype(request_type, exercise_options):
        # raises exception if not allowed, passes otherwise
        if request_type == Request.NORMAL_REQUEST:
            if not exercise_options.use_requests:
                raise SuspiciousOperation('normal requests are not allowed by this exercise')
        elif request_type == Request.SUBMISSION_REQUEST:
            if not exercise_options.use_submission_list:
                raise SuspiciousOperation('submission requests are not allowed by this exercise')
        elif request_type == Request.SPECIAL_REQUEST:
            if not exercise_options.use_special_list:
                raise SuspiciousOperation('special requests are not allowed by this exercise')
        else:
            raise SuspiciousOperation('unimplemented requesttype')
    
    @csrf_exempt
    def request(request):
        '''
        Create and delete requests.
        '''
    
        hostname = remote_cip_hostname(request)
        host = get_object_or_404(Host, host_name=hostname)
    
        put = QueryDict(request.body)
        try:
            exercise_id = put.get('exercise')
            exercise = get_object_or_404(Exercise, id=exercise_id)
        except KeyError:
            raise SuspiciousOperation('missing fields')
    
        # get type of request
        try:
            req_type = __request_type_to_field(put['request_type'])
        except KeyError:
            raise SuspiciousOperation('invalid request type')
    
    
        # there must be a graphically logged in user at this host!
        if not host.occupied:
            raise SuspiciousOperation('unoccupied host')
    
        # and or delete requests now.
        if request.method == 'PUT':
    
            # Check if exercise happens at the moment
            now = datetime.datetime.now()
            if not (now.weekday() == exercise.weekday and
                    exercise.start <= now.time() <= exercise.end):
                raise SuspiciousOperation('invalid request time')
    
            # Check if Exercise uses requests at all
            try:
               exercise_options = ExerciseOption.objects.get(exercise_name=exercise.name)
            except ObjectDoesNotExist:
                raise SuspiciousOperation('requests not allowed by exercise')
    
            # check if this kind of request is allowed by the exercise
            __check_allowance_of_requesttype(req_type, exercise_options)
    
            if exercise_options.use_highprior:
                # only evaluate username if exercise is highprior
                # does only affect normal requests on webinterface
                try:
                    user = request.META['REMOTE_USER']
                except KeyError:
                    user = "WindowsCIP"
    
                priority = exercise.exerciseuser_set.\
                    filter(name=user).exists()
            else:
                priority = False
    
            # Check if user is okay with saving username for statistics
            allow_statistic = request.COOKIES.get('allow_statistic')
            if allow_statistic == "true":
                try:
                    user = request.META['REMOTE_USER']
                except KeyError:
                    user = "WindowsCIP"
                hashed_username = __hash_username(user)
            else:
                hashed_username = "NOT_ALLOWED"
    
            with transaction.atomic():
                r, created = Request.objects.get_or_create(
                        defaults={'priority': False, 'username': 'NOT_ALLOWED', 'request_type': req_type},
                    host=hostname, exercise=exercise,
                )
                if created:
                    r.username=hashed_username # set statisticrequest
                    r.priority = priority
                    r.save()
                else:
                    pass #otherwise, request was send twice, just ignore it.
    
        elif request.method == 'DELETE':
             Request.objects.filter(
                host=hostname,
                exercise=exercise).delete()
        else:
            return HttpResponseNotAllowed(['PUT', 'DELETE'])
    
        return _requests(request, send_hostname=hostname)
    
    
    def requests(request):
        '''
        Provide data about current requests.
        '''
    
        hostname = remote_cip_hostname(request)
    
        return _requests(request, send_hostname=hostname)
    
    
    def _requests(request, send_hostname=None):
        data = {
            'age': int(datetime.datetime.now().timestamp()),
            'requests': collections.defaultdict(list),
            'exercises': collections.defaultdict(list),
            'hostname': send_hostname,
        }
    
        for r in Request.objects.\
                prefetch_related('exercise', 'exercise__room').all():
    
            exercise = r.exercise
    
            data['requests'][exercise.room.name].append({
                'host': r.host,
                'time': int(r.time.timestamp()),
                'priority': r.priority,
                'request_type': r.request_type,
                'exercise': exercise.id,
            })
    
        data['exercises'] = _get_lectures_now()
        data['exercises_today'] = _get_lectures_today()
        data['configuration'] = _get_lecture_configuration()
        data['temperatures'] = _get_temperatures()
    
        indent = None
        if settings.DEBUG:
            indent = 4
    
        return JsonResponse(data, json_dumps_params={'indent': indent})
    
    
    def _get_temperatures():
        temperatures = {}
    
        for room in Room.objects.all():
            temperatures[room.name] = cache.get('temp_' + room.name)
            if temperatures[room.name] is None:
                if room.temp_hosts == '':
                    temperatures[room.name] = 'N/A'
                else:
                    try:
                        temps = []
                        for thost in room.temp_hosts.split(','):
                            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                            s.settimeout(1)
                            s.connect((thost + '.cs.fau.de', 16842))
                            temp_float = float(s.recv(1024).decode().strip())
                            temps.append(str(round(temp_float, 1)))
                        temperatures[room.name] = '/'.join(temps) + ' °C'
                    except Exception as e:
                        temperatures[room.name] = 'N/A'
    
                cache.set('temp_' + room.name, temperatures[room.name], 10)
    
        return temperatures
    
    
    def _get_lectures_now():
        ex_today = _get_lectures_today()
    
        ex_now = {}
    
        time_now = datetime.datetime.now().time()
    
        for r in ex_today:
            ex_now[r] = [k for k in ex_today[r] if k['display_start'] <= time_now < k['display_end']]
    
        return ex_now
    
    def _get_lectures_today():
    
        exercises = collections.defaultdict(list)
        for r in _get_rooms(False):
            exercises[r.name] = []
    
        # exercises which use at least one of our request-lists
        cipmap_lectures = set(ExerciseOption.objects.filter(
            Q(use_requests=True) |
            Q(use_submission_list=True) |
            Q(use_special_list=True)
            ).values_list('exercise_name', flat=True))
    
        weekday = datetime.datetime.now().weekday()
        for e in Exercise.objects.select_related('room').filter(weekday=weekday):
            exercises[e.room.name].append({
                'id': e.id,
                'name': e.name,
                'active': e.name in cipmap_lectures,
                'request_start': e.start,
                'request_end': e.end,
                'display_start': e.display_start,
                'display_end': e.display_end,
            })
    
        for r in exercises:
            exercises[r].sort(key=lambda x: (-x['active'], x['name']))
    
        return exercises
    
    
    def _get_lecture_configuration():
        configuration = {}
    
        for l in ExerciseOption.objects.all():
            d = {k: getattr(l, k) for k in ['use_requests', 'keep_requests',
                                            'use_submission_list',
                                            'use_special_list']}
    
            if d['use_requests']:
                d['use_highprior'] = l.use_highprior
    
            if d['use_special_list']:
                d['special_list_name'] = l.special_list_name
                d['special_list_button'] = l.special_list_button
    
            configuration[l.exercise_name] = d
    
        return configuration
    
    
    def map(request):
        map_file = open(settings.MAP_PATH).read()
        map_json = json.loads(map_file)
    
        map_json['buero'] = {
            'computer': [
                {
                    'x': 0,
                    'y': 0,
                    'id': 'faui03a',
                },
                {
                    'x': 1,
                    'y': 0,
                    'id': 'faui03b',
                },
                {
                    'x': 2,
                    'y': 0,
                    'id': 'faui03c',
                },
                {
                    'x': 3,
                    'y': 0,
                    'id': 'faui03d',
                },
                {
                    'x': 4,
                    'y': 0,
                    'id': 'faui03e',
                },
                {
                    'x': 5,
                    'y': 0,
                    'id': 'faui03f',
                },
                {
                    'x': 0,
                    'y': 1,
                    'id': 'faui03g',
                },
                {
                    'x': 1,
                    'y': 1,
                    'id': 'faui03h',
                },
                {
                    'x': 2,
                    'y': 1,
                    'id': 'faui03l',
                },
                {
                    'x': 3,
                    'y': 1,
                    'id': 'faui03m',
                },
                {
                    'x': 4,
                    'y': 1,
                    'id': 'faui03n',
                }
            ],
            'door': {
                'position': 0,
                'offset': -42,
            }
        }
        map_json['fsi'] = {
            'computer': [
                {  # FSI Inf
                    'x': 0,
                    'y': 0,
                    'id': 'faui03i',
                },
                {  # FSI CE
                    'x': 2,
                    'y': 0,
                    'id': 'faui03j',
                },
                {  # FSI MT
                    'x': 4,
                    'y': 0,
                    'id': 'faui03k',
                }
            ],
            'door': {
                'position': 0,
                'offset': -42,
            }
        }
    
        # Insert room names
        for room in _get_rooms(False):
            map_json[room.name]['name'] = room.name_long
            map_json[room.name]['number'] = room.name_number
    
        indent = None
        if settings.DEBUG:
            indent = 4
    
        context = {'map_data': json.dumps(map_json, indent=indent)}
        return render(request, 'server/map.js', context, 'application/javascript')