mirror of https://github.com/nucypher/nucypher.git
Felix database skeleton and registrtion view stubbing
parent
ce39f92555
commit
3fbb5ef426
|
@ -3,6 +3,7 @@ import os
|
|||
from os.path import dirname, abspath
|
||||
|
||||
import click
|
||||
import maya
|
||||
from flask import Flask, render_template, Response
|
||||
from sqlalchemy import create_engine, Column, Integer, String
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
@ -111,35 +112,41 @@ class Felix(Character):
|
|||
|
||||
_default_crypto_powerups = [SigningPower]
|
||||
|
||||
def __init__(self, db_filepath, rest_host, rest_port, *args, **kwargs):
|
||||
def __init__(self,
|
||||
db_filepath: str,
|
||||
rest_host: str,
|
||||
rest_port: int,
|
||||
*args, **kwargs):
|
||||
|
||||
# Character
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
#
|
||||
# Felix
|
||||
#
|
||||
|
||||
# Network
|
||||
self.rest_port = rest_port
|
||||
self.rest_host = rest_host
|
||||
self.db_filepath = db_filepath
|
||||
self.rest_app = None
|
||||
|
||||
# Database
|
||||
self.db_filepath = db_filepath
|
||||
self.db = None
|
||||
self.engine = create_engine(f'sqlite://{self.db_filepath}', convert_unicode=True)
|
||||
|
||||
# Banner
|
||||
self.log.info(FELIX_BANNER.format(bytes(self.stamp).hex()))
|
||||
|
||||
def init_db(self):
|
||||
db_session = scoped_session(sessionmaker(autocommit=False,
|
||||
autoflush=False,
|
||||
bind=self.engine))
|
||||
Base = declarative_base()
|
||||
Base.query = db_session.query_property()
|
||||
|
||||
Base.metadata.create_all(bind=self.engine)
|
||||
|
||||
def make_web_app(self):
|
||||
from flask import request
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
# WSGI Service
|
||||
self.rest_app = Flask("faucet", template_folder=TEMPLATES_DIR)
|
||||
|
||||
# Flask Settings
|
||||
self.rest_app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite://{self.db_filepath}'
|
||||
self.rest_app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{self.db_filepath}'
|
||||
self.rest_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
self.rest_app.secret_key = "flask rocks!" # FIXME: NO!!!
|
||||
|
||||
|
@ -152,19 +159,31 @@ class Felix(Character):
|
|||
id = self.db.Column(self.db.Integer, primary_key=True)
|
||||
address = self.db.Column(self.db.String)
|
||||
joined = self.db.Column(self.db.String)
|
||||
amount_received = self.db.Column(self.db.Integer, default=0)
|
||||
last_airdrop = self.db.Column(self.db.String, nullable=True)
|
||||
|
||||
rest_app = self.rest_app
|
||||
|
||||
@rest_app.route("/")
|
||||
@rest_app.route("/", methods=['GET'])
|
||||
def home():
|
||||
return render_template('felix.html')
|
||||
|
||||
@rest_app.route("/register")
|
||||
@rest_app.route("/register", methods=['POST'])
|
||||
def register():
|
||||
try:
|
||||
recipient = Recipient(address=request.form['address'], joined=str(maya.now()))
|
||||
self.db.session.add(recipient)
|
||||
self.db.session.commit()
|
||||
except Exception as e:
|
||||
self.log.critical(str(e))
|
||||
return Response(status=200)
|
||||
|
||||
return rest_app
|
||||
|
||||
def create_tables(self) -> None:
|
||||
self.db.create_all()
|
||||
return
|
||||
|
||||
def start(self, host: str, port: int, dry_run: bool = False):
|
||||
|
||||
# Server
|
||||
|
|
|
@ -43,64 +43,77 @@ def felix(click_config,
|
|||
registry_filepath):
|
||||
|
||||
if action == "init":
|
||||
"""Create a brand-new persistent Ursula"""
|
||||
"""Create a brand-new Felix"""
|
||||
|
||||
# Validate "Init" Input
|
||||
if not network:
|
||||
raise click.BadArgumentUsage('--network is required to initialize a new configuration.')
|
||||
|
||||
# Acquire Keyring Password
|
||||
if not config_root: # Flag
|
||||
config_root = click_config.config_file # Envvar
|
||||
new_password = click_config._get_password(confirm=True)
|
||||
|
||||
ursula_config = FelixConfiguration.generate(password=click_config._get_password(confirm=True),
|
||||
config_root=config_root,
|
||||
rest_host=host,
|
||||
rest_port=discovery_port,
|
||||
db_filepath=db_filepath,
|
||||
domains={network} if network else None,
|
||||
checksum_public_address=checksum_address,
|
||||
no_registry=no_registry,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_uri=provider_uri,
|
||||
poa=poa)
|
||||
new_felix_config = FelixConfiguration.generate(password=new_password,
|
||||
config_root=config_root,
|
||||
rest_host=host,
|
||||
rest_port=discovery_port,
|
||||
db_filepath=db_filepath,
|
||||
domains={network} if network else None,
|
||||
checksum_public_address=checksum_address,
|
||||
no_registry=no_registry,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_uri=provider_uri,
|
||||
poa=poa)
|
||||
|
||||
painting.paint_new_installation_help(new_configuration=ursula_config,
|
||||
# Paint Help
|
||||
painting.paint_new_installation_help(new_configuration=new_felix_config,
|
||||
config_root=config_root,
|
||||
config_file=config_file)
|
||||
return
|
||||
|
||||
elif action == 'run':
|
||||
return # <-- do not remove (conditional flow control)
|
||||
|
||||
# Domains -> bytes | or default
|
||||
domains = [bytes(network, encoding='utf-8')] if network else None
|
||||
#
|
||||
# Authentication Configurations
|
||||
#
|
||||
|
||||
# Load Ursula from Configuration File
|
||||
try:
|
||||
felix_config = FelixConfiguration.from_configuration_file(filepath=config_file,
|
||||
domains=domains,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_uri=provider_uri,
|
||||
rest_host=host,
|
||||
rest_port=port,
|
||||
db_filepath=db_filepath,
|
||||
poa=poa)
|
||||
except FileNotFoundError:
|
||||
click.secho("No Felix Configuration File Found.")
|
||||
raise click.Abort
|
||||
# Domains -> bytes | or default
|
||||
domains = [bytes(network, encoding='utf-8')] if network else None
|
||||
|
||||
# Teacher Ursula
|
||||
# Load Ursula from Configuration File with overrides
|
||||
try:
|
||||
felix_config = FelixConfiguration.from_configuration_file(filepath=config_file,
|
||||
domains=domains,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_uri=provider_uri,
|
||||
rest_host=host,
|
||||
rest_port=port,
|
||||
db_filepath=db_filepath,
|
||||
poa=poa)
|
||||
except FileNotFoundError:
|
||||
click.secho(f"No Felix configuration file found at {config_file}. "
|
||||
f"Check the filepath or run 'nucypher felix init' to create a new system configuration.")
|
||||
raise click.Abort
|
||||
|
||||
else:
|
||||
|
||||
# Produce Teacher Ursulas
|
||||
teacher_uris = [teacher_uri] if teacher_uri else list()
|
||||
teacher_nodes = actions.load_seednodes(teacher_uris=teacher_uris,
|
||||
min_stake=min_stake,
|
||||
federated_only=False,
|
||||
network_middleware=click_config.middleware)
|
||||
|
||||
# Felix
|
||||
# Produce Felix
|
||||
click_config.unlock_keyring(character_configuration=felix_config)
|
||||
FELIX = felix_config.produce(domains=network, known_nodes=teacher_nodes)
|
||||
FELIX.make_web_app() # attach web application, but dont start service
|
||||
|
||||
# Start web services
|
||||
FELIX.make_web_app()
|
||||
if action == "createdb": # Initialize Database
|
||||
FELIX.create_tables()
|
||||
|
||||
elif action == 'run': # Start web services
|
||||
FELIX.start(host=host, port=port, dry_run=dry_run)
|
||||
|
||||
else:
|
||||
else: # Error
|
||||
raise click.BadArgumentUsage("No such argument {}".format(action))
|
||||
|
|
|
@ -21,6 +21,10 @@ import os
|
|||
from constant_sorrow.constants import (
|
||||
UNINITIALIZED_CONFIGURATION
|
||||
)
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
from nucypher.config.keyring import NucypherKeyring
|
||||
from nucypher.config.node import NodeConfiguration
|
||||
|
@ -133,9 +137,13 @@ class FelixConfiguration(NodeConfiguration):
|
|||
from nucypher.characters.chaotic import Felix
|
||||
|
||||
def __init__(self, db_filepath: str = None, *args, **kwargs) -> None:
|
||||
self.db_filepath = db_filepath or self.DEFAULT_DB_FILEPATH
|
||||
|
||||
# Character
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Felix
|
||||
self.db_filepath = db_filepath or os.path.join(self.config_root, self.DEFAULT_DB_NAME)
|
||||
|
||||
# Character
|
||||
_CHARACTER_CLASS = Felix
|
||||
_NAME = _CHARACTER_CLASS.__name__.lower()
|
||||
|
|
|
@ -16,14 +16,14 @@ from nucypher.utilities.sandbox.constants import (
|
|||
@pytest_twisted.inlineCallbacks
|
||||
def test_run_felix(click_runner, federated_ursulas):
|
||||
|
||||
args = ('felix', 'init',
|
||||
'--config-root', MOCK_CUSTOM_INSTALLATION_PATH_2,
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--no-registry',
|
||||
'--provider-uri', TEST_PROVIDER_URI)
|
||||
init_args = ('felix', 'init',
|
||||
'--config-root', MOCK_CUSTOM_INSTALLATION_PATH_2,
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--no-registry',
|
||||
'--provider-uri', TEST_PROVIDER_URI)
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}'
|
||||
result = click_runner.invoke(nucypher_cli, args, input=user_input, catch_exceptions=False)
|
||||
result = click_runner.invoke(nucypher_cli, init_args, input=user_input, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
|
||||
configuration_file_location = os.path.join(MOCK_CUSTOM_INSTALLATION_PATH_2, 'felix.config')
|
||||
|
@ -52,7 +52,10 @@ def test_run_felix(click_runner, federated_ursulas):
|
|||
test_client = web_app.test_client()
|
||||
|
||||
response = test_client.get('/')
|
||||
assert response == 200
|
||||
assert response.status_code == 200
|
||||
|
||||
response = test_client.post('/register', data={'address': '0xdeadbeef'})
|
||||
assert response.status_code == 200
|
||||
|
||||
d = threads.deferToThread(run_felix)
|
||||
d.addCallback(request_felix_landing_page)
|
||||
|
|
|
@ -30,7 +30,7 @@ globalLogPublisher.removeObserver(logToSentry)
|
|||
|
||||
# Disable click sentry and file logging
|
||||
NucypherClickConfig.log_to_sentry = False
|
||||
NucypherClickConfig.log_to_file = False
|
||||
NucypherClickConfig.log_to_file = True
|
||||
|
||||
# Crash on server error by default
|
||||
WebEmitter._crash_on_error_default = False
|
||||
|
|
Loading…
Reference in New Issue