Files @ 1585155d7c8a
Branch filter:

Location: FVDE/ennstatus/ennstatus/api/views.py

Dennis Fink
Use new model for servers
import ipaddress
import json

from datetime import datetime

from flask import (Blueprint, request, current_app, jsonify, render_template,
                   abort)

import strict_rfc3339
import pygeoip

from ennstatus.status.functions import (single_server, all_servers,
                                        all_servers_by_type)
from .model import Server


api_page = Blueprint('api', __name__)
gi4 = pygeoip.GeoIP('/usr/share/GeoIP/GeoIP.dat', pygeoip.MEMORY_CACHE)
gi6 = pygeoip.GeoIP('/usr/share/GeoIP/GeoIPv6.dat', pygeoip.MEMORY_CACHE)


@api_page.route('/update', methods=('POST',))
def update():

    current_app.logger.info('Handling update')
    if current_app.debug:
        accepted_ips = ['127.0.0.1']
    else:
        accepted_ips = current_app.config.get('ENNSTATUS_ACCEPTED_IPS', [])

    if request.remote_addr not in accepted_ips:
        current_app.logger.warn('Unallowed IP %s tried to update data!'
                                % request.remote_addr)
        return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'}

    data = request.get_json()

    if data is None:
        current_app.logger.info('No JSON data supplied!')
        return 'No JSON data supplied!\n', 400, {'Content-Type': 'text/plain'}

    if 'ip' in data:
        ip = data['ip']
    elif 'ip6' in data:
        ip = data['ip6']
    else:
        ip = request.remote_addr

    try:
        ip = ipaddress.ip_address(ip)
    except ipaddress.AddressValueError:
        return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'}

    if ip.version == 4:
        data['country'] = gi4.country_name_by_addr(str(ip))
    elif ip.version == 6:
        data['country'] = gi6.country_name_by_addr(str(ip))
    else:
        data['country'] = None

    data['last_updated'] = strict_rfc3339.timestamp_to_rfc3339_utcoffset(
        datetime.utcnow().timestamp()
    )
    data['status'] = True

    try:
        server = Server.from_json(json.dumps(data))
    except Exception as e:
        current_app.logger.warning(' '.join([str(e), str(data)]))
        return str(e), 409, {'Content-Type': 'text/plain'}

    if server.type in ('exit', 'relay'):
        server.update_weights()

    try:
        server.save()
    except Exception as e:
        current_app.logger.error(str(e))
        return str(e), 500, {'Content-Type': 'text/plain'}

    current_app.logger.info('Return result')
    return (server.json(), 201,
            {'Location': '/api/export/json/single?server_name=%s'
             % server.name})


@api_page.route('/export', defaults={'server_type': 'all',
                                     'export_format': 'json'})
@api_page.route('/export/<any("json", "xml"):export_format>',
                defaults={'server_type': 'all'})
@api_page.route(('/export/<any("json", "xml"):export_format>'
                 '/<any("all", "exit", "bridge", "relay", "single")'
                 ':server_type>'))
def export(export_format, server_type):

    current_app.logger.info('Handling export')
    if server_type == 'single':
        server_name = request.args.get('server_name', None)
        if server_name is not None:
            server = single_server(server_name)
            if server:
                if export_format == 'json':
                    current_app.logger.info('Returning server as json!')
                    return (server.json(), 200,
                            {'Content-Type': 'application/json'})
                else:
                    current_app.logger.info('Returning server as xml!')
                    return (
                        render_template(
                            'api/export/xml/single_server.xml',
                            server=server),
                        200, {'Content-Type': 'text/xml'})
            else:
                current_app.logger.warning('Server not found!')
                return ('Server not found!\n',
                        404, {'Content-Type': 'text/plain'})
        else:
            current_app.logger.warning('No server_name specified!')
            return ('No server_name specified!\n',
                    400, {'Content-Type': 'text/plain'})

    else:
        if server_type == 'all':
            current_app.logger.info('Getting all servers!')
            servers = [server.json() for server in all_servers()]
        else:
            current_app.logger.info('Getting all %s!' % server_type)
            servers = list(all_servers_by_type(server_type.lower()))

        if export_format == 'json':
            current_app.logger.info('Returning as json!')
            return str(servers)
        else:
            current_app.logger.info('Returning as xml!')
            return (render_template('api/export/xml/network.xml',
                                    servers=servers),
                    200, {'Content-Type': 'text/xml'})