muizenval

Observe mouse traps remotely
Log | Files | Refs

socket.py (5534B)


      1 from datetime import datetime
      2 import os
      3 import random
      4 import sys
      5 from typing import Dict
      6 from flask import request, jsonify
      7 from flask_login import current_user
      8 from flask_socketio import emit
      9 
     10 from .app import app, db, socket, domain
     11 from .models import Statistic, Trap, User
     12 
     13 current_user: User
     14 
     15 sockets: Dict[int, str] = {}
     16 
     17 accuracy_min = 80
     18 
     19 
     20 def make_token():
     21     return ''.join(random.choice('0123456789abcdefghijklmnopqrstuvwxyz') for _ in range(16))
     22 
     23 
     24 @app.post("/api/hello")
     25 def register_trap():
     26     req = request.get_json(True)
     27     if not req:
     28         return jsonify(dict(error='invalid-request'))
     29 
     30     res = dict()
     31     if 'token' not in req or not req['token'] or not Trap.query.filter_by(token=req['token']).first():
     32         while True:
     33             token = make_token()
     34             if not Trap.query.filter_by(token=token).first():
     35                 break
     36 
     37         trap = Trap(token=token, last_status=datetime.now())
     38         db.session.add(trap)
     39         db.session.commit()
     40         res['token'] = token
     41     else:
     42         trap: Trap = Trap.query.filter_by(token=req['token']).first()
     43 
     44     res['location_search'] = trap.location_search
     45 
     46     if 'domain' not in req or req['domain'] != domain:
     47         res['domain'] = domain
     48 
     49     return jsonify(res)
     50 
     51 
     52 @app.post("/api/update")
     53 def update_status():
     54     req = request.get_json(True)
     55     if not req:
     56         return jsonify(dict(error='invalid-request'))
     57 
     58     trap: Trap = Trap.query.filter_by(token=req['token']).first()
     59     if not trap:
     60         return jsonify(dict(error='invalid-token'))
     61 
     62     if not trap.caught and req['trap']:
     63         if trap.owner:
     64             stc = Statistic(user=trap.owner, trap=trap.id, date=datetime.now())
     65             db.session.add(stc)
     66         if os.environ.get('SEND_MAIL', '0') != '0':
     67             os.system(
     68                 f"echo \"<p>Uw muizenval '{trap.name}' heeft iets gevangen!<br>Ga naar <a href='http://muizenval.tk/traps'>uw dashboard</a>.</p><p>Groetjes Team Benni!</p>\" | mailx -a 'Content-Type: text/html' -s 'Muizenval is geactiveerd' {trap.owner_class().email}")        # type: ignore
     69         print('Email sent!')
     70 
     71     trap.last_status = datetime.now()
     72     trap.caught = req['trap']
     73     trap.battery = req['battery']
     74     trap.temperature = req['temperature']
     75     trap.charging = req['charging']
     76     trap.location_searching = req['searching']
     77     if trap.location_search:
     78         trap.location_satellites = req['satellites']
     79         if req['accuracy'] != 0:
     80             trap.location_acc = req['accuracy']
     81             trap.location_lat = req['latitude']
     82             trap.location_lon = req['longitude']
     83 
     84     db.session.commit()
     85 
     86     if trap.owner and trap.owner in sockets:
     87         socket.emit('trap-change', trap.to_json(), to=sockets[trap.owner])
     88         socket.emit('statistics', make_statistics(
     89             trap.owner), to=sockets[trap.owner])
     90 
     91     return jsonify(dict(location_search=trap.location_search))
     92 
     93 
     94 def make_statistics(user: int):
     95     year = datetime.now().year
     96     months = [0] * 12
     97     table = []
     98     stc: Statistic
     99     for stc in Statistic.query.filter_by(user=user):
    100         table.append([stc.id, Trap.query.get(stc.trap).name,
    101                      stc.date.strftime('%d-%m-%y %H:%M')])
    102         if stc.date.year == year:
    103             months[stc.date.month-1] += 1
    104 
    105     return dict(months=months, table=table)
    106 
    107 
    108 @socket.on('connect')
    109 def socket_connect():
    110     if not current_user.is_authenticated:
    111         return
    112 
    113     sockets[current_user.id] = request.sid  # type: ignore
    114 
    115     for trap in Trap.query.filter_by(owner=current_user.id):
    116         emit('trap-change', trap.to_json())
    117 
    118     emit('statistics', make_statistics(current_user.id))
    119 
    120 
    121 @socket.on('disconnect')
    122 def socket_disconnect():
    123     if not current_user.is_authenticated:
    124         return
    125 
    126     if current_user.id in sockets:
    127         del sockets[current_user.id]
    128 
    129 
    130 @socket.on('token')
    131 def socket_token(token):
    132     if not token or not current_user.is_authenticated:
    133         return
    134 
    135     trap: Trap = Trap.query.filter_by(token=token).first()
    136 
    137     if trap.owner != current_user.id:
    138         trap.owner = current_user.id
    139         trap.owned_date = datetime.now()
    140         db.session.commit()
    141 
    142         emit('trap-change', trap.to_json())
    143 
    144 
    145 @socket.on('location-search')
    146 def socket_location(data):
    147     if not data or not current_user.is_authenticated:
    148         return
    149 
    150     print(data['id'])
    151     trap: Trap = Trap.query.get(data['id'])
    152     if not trap or trap.owner != current_user.id:
    153         return
    154 
    155     trap.location_search = data['search']
    156     db.session.commit()
    157 
    158     emit('trap-change', trap.to_json())
    159 
    160 
    161 @socket.on('delete')
    162 def socket_delete(data):
    163     if not data or not current_user.is_authenticated:
    164         return
    165 
    166     print(data['id'])
    167     trap: Trap = Trap.query.get(data['id'])
    168     if not trap or trap.owner != current_user.id:
    169         return
    170 
    171     Statistic.query.filter_by(trap=trap.id).delete()
    172 
    173     trap.owner = False
    174     trap.name = "n/a"
    175 
    176     db.session.commit()
    177 
    178 
    179 @socket.on('name')
    180 def socket_name(data):
    181     if not data or not current_user.is_authenticated:
    182         return
    183 
    184     trap: Trap = Trap.query.get(data['id'])
    185     if not trap or trap.owner != current_user.id:
    186         return
    187 
    188     trap.name = data['name']
    189     db.session.commit()
    190 
    191     emit('trap-change', trap.to_json())
    192 
    193 
    194 @socket.on('delete-statistic')
    195 def socket_delete_statistic(id: int):
    196     if not id or not current_user.is_authenticated:
    197         return
    198 
    199     Statistic.query.filter_by(id=id).delete()
    200 
    201     db.session.commit()
    202 
    203     emit('statistics', make_statistics(current_user.id))