1
0
mirror of https://github.com/avatao-content/test-tutorial-framework synced 2024-11-14 15:47:17 +00:00

Merge branch 'message-types'

This commit is contained in:
Kristóf Tóth 2018-06-04 22:19:39 +02:00
commit cb9e673a68
6 changed files with 63 additions and 30 deletions

View File

@ -185,7 +185,7 @@ It also manages the FSM.
As you can see this file is set up to start with the container in `solvable/supervisor/tfw_server.conf`. As you can see this file is set up to start with the container in `solvable/supervisor/tfw_server.conf`.
`event_handler_main.py` contains example usage of our pre-defined event handlers written in Python3. `event_handler_main.py` contains example usage of our pre-defined event handlers written in Python3.
As you can see they run in a separate process (set up in `solvable/supervisor/event_handlers.conf`). As you can see they run in a separate process (set up in `solvable/supervisor/event_handler_main.conf`).
These event handlers could be implemented in any language that has ZMQ bindings. These event handlers could be implemented in any language that has ZMQ bindings.
Note that you don't have to use all our event handlers. Note that you don't have to use all our event handlers.
@ -204,7 +204,7 @@ When creating your own challenge the process should be the following:
- Set it up to run: `solvable/supervisor/tfw_server.conf` - Set it up to run: `solvable/supervisor/tfw_server.conf`
4. Create event handlers connecting to the `TFWServer` handling events you want to process: 4. Create event handlers connecting to the `TFWServer` handling events you want to process:
- Create an event handler server: `solvable/src/event_handler_main.py` - Create an event handler server: `solvable/src/event_handler_main.py`
- Set it up to run: `solvable/supervisor/event_handlers.conf` - Set it up to run: `solvable/supervisor/event_handler_main.conf`
5. Modify the frontend in `solvable/frontend` to fit your challenge 5. Modify the frontend in `solvable/frontend` to fit your challenge
- This usually involves using our pre-made components - This usually involves using our pre-made components
- And perhaps doing some of your own stuff, like: - And perhaps doing some of your own stuff, like:

View File

@ -2,7 +2,8 @@ from ast import literal_eval
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from tfw.components import IdeEventHandler, TerminalEventHandler, ProcessManagingEventHandler, BashMonitor from tfw.components import IdeEventHandler, TerminalEventHandler
from tfw.components import ProcessManagingEventHandler, BashMonitor
from tfw.components import TerminalCommands, LogMonitoringEventHandler from tfw.components import TerminalCommands, LogMonitoringEventHandler
from tfw.networking import MessageSender, TFWServerConnector from tfw.networking import MessageSender, TFWServerConnector
from tfw.config import TFWENV from tfw.config import TFWENV
@ -13,6 +14,10 @@ LOG = logging.getLogger(__name__)
def cenator(history): def cenator(history):
"""
Logs commands executed in terminal to messages.
!! Please remove from production code. !!
"""
LOG.debug('User executed command: "%s"', history[-1]) LOG.debug('User executed command: "%s"', history[-1])
MessageSender().send('JOHN CENA', f'You\'ve executed "{history[-1]}"') MessageSender().send('JOHN CENA', f'You\'ve executed "{history[-1]}"')
@ -20,7 +25,7 @@ def cenator(history):
class TestCommands(TerminalCommands): class TestCommands(TerminalCommands):
""" """
Some example commands useful for debugging. Some example commands useful for debugging.
Please remove from production code and inherit your own !! Please remove from production code !! and inherit your own
class from TerminalCommands if you need to define custom class from TerminalCommands if you need to define custom
commands in your challenge. commands in your challenge.
""" """
@ -38,7 +43,7 @@ class TestCommands(TerminalCommands):
'key': 'shell', 'key': 'shell',
'data': { 'data': {
'command': 'write', 'command': 'write',
'shellcmd': f'sendmessage {message_template}' 'value': f'sendmessage {message_template}'
} }
}) })
else: else:
@ -50,20 +55,22 @@ class TestCommands(TerminalCommands):
This can speed up development when combined with mounting This can speed up development when combined with mounting
volumes from host to container. volumes from host to container.
""" """
seppuku = ('nohup sh -c "supervisorctl restart tfwserver event_handler_main" &> /dev/null & ' seppuku = (
'clear && echo "Committed seppuku! :)" && sleep infinity') 'nohup sh -c "supervisorctl restart tfwserver event_handler_main" &> /dev/null & '
'clear && echo "Committed seppuku! :)" && sleep infinity'
)
uplink = TFWServerConnector() uplink = TFWServerConnector()
uplink.send_to_eventhandler({ uplink.send_to_eventhandler({
'key': 'shell', 'key': 'shell',
'data': { 'data': {
'command': 'write', 'command': 'write',
'shellcmd': f'{seppuku}\n' 'value': f'{seppuku}\n'
} }
}) })
uplink.send({ uplink.send({
'key': 'dashboard', 'key': 'dashboard',
'data': { 'data': {
'command': 'reload_frontend' 'command': 'reloadFrontend'
} }
}) })
@ -73,8 +80,7 @@ if __name__ == '__main__':
key='ide', key='ide',
allowed_directories=[TFWENV.IDE_WD, TFWENV.WEBSERVICE_DIR], allowed_directories=[TFWENV.IDE_WD, TFWENV.WEBSERVICE_DIR],
directory=TFWENV.IDE_WD, directory=TFWENV.IDE_WD,
exclude=['*.pyc'], exclude=['*.pyc']
additional_watched_directories=[TFWENV.WEBSERVICE_DIR]
) )
terminal = TerminalEventHandler( # Web shell backend terminal = TerminalEventHandler( # Web shell backend
key='shell', key='shell',
@ -92,10 +98,9 @@ if __name__ == '__main__':
) )
eventhandlers = {ide, terminal, processmanager, logmonitor} eventhandlers = {ide, terminal, processmanager, logmonitor}
terminal.historymonitor.subscribe_callback(cenator)
commands = TestCommands(bashrc=f'/home/{TAOENV.USER}/.bashrc') commands = TestCommands(bashrc=f'/home/{TAOENV.USER}/.bashrc')
terminal.historymonitor.subscribe_callback(commands.callback) terminal.historymonitor.subscribe_callback(commands.callback)
terminal.historymonitor.subscribe_callback(cenator)
try: try:
IOLoop.instance().start() IOLoop.instance().start()

View File

@ -6,9 +6,11 @@ from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///db.db', convert_unicode=True) engine = create_engine('sqlite:///db.db', convert_unicode=True)
session_factory = sessionmaker(autocommit=False, session_factory = sessionmaker(
autocommit=False,
autoflush=False, autoflush=False,
bind=engine) bind=engine
)
@contextmanager @contextmanager

View File

@ -10,7 +10,9 @@ BASEURL = getenv('BASEURL', '')
init_db() init_db()
app = Flask(__name__) app = Flask(__name__)
app.secret_key = urandom(32) app.secret_key = urandom(32)
app.jinja_env.globals.update(get_url=lambda endpoint: f'{BASEURL}{url_for(endpoint)}') # pylint: disable=no-member app.jinja_env.globals.update( # pylint: disable=no-member
get_url=lambda endpoint: f'{BASEURL}{url_for(endpoint)}'
)
def get_db_session(): def get_db_session():
@ -47,22 +49,33 @@ def index():
@app.route('/register', methods=['GET', 'POST']) @app.route('/register', methods=['GET', 'POST'])
def register(): def register():
if request.method == 'POST': if request.method == 'POST':
if not all([request.form.get('username'), form_filled_out = all([
request.form.get('username'),
request.form.get('password'), request.form.get('password'),
request.form.get('passwordconfirm')]): request.form.get('passwordconfirm')
])
if not form_filled_out:
return render_template('register.html', alert='You need to fill everything.') return render_template('register.html', alert='You need to fill everything.')
if request.form['password'] != request.form['passwordconfirm']: if request.form['password'] != request.form['passwordconfirm']:
return render_template('register.html', alert='Passwords do not match! Please try again.') return render_template('register.html', alert='Passwords do not match! Please try again.')
try: try:
UserOps(request.form.get('username'), UserOps(
request.form.get('username'),
request.form.get('password'), request.form.get('password'),
get_db_session()).register() get_db_session()
).register()
except UserExistsError: except UserExistsError:
return render_template('register.html', alert='Username already in use.') return render_template('register.html', alert='Username already in use.')
return render_template('login.html', success=('Account "{}" successfully registered. ' return render_template(
'You can log in now!'.format(request.form['username']))) 'login.html',
success=(
'Account "{}" successfully registered. '
'You can log in now!'.format(request.form['username'])
)
)
return render_template('register.html') return render_template('register.html')

View File

@ -23,9 +23,16 @@ class UserOps:
:raises InvalidCredentialsError: :raises InvalidCredentialsError:
User does not exist or password provided is invalid User does not exist or password provided is invalid
""" """
user = self.db_session.query(User).filter(User.username == self.username).first() user = self.db_session.query(User).filter(
User.username == self.username
).first()
if not user or not PasswordHasher.verify(self.password, user.passwordhash): passw_is_correct = PasswordHasher.verify(
self.password,
user.passwordhash
)
if not user or not passw_is_correct:
self.log(f'Invalid credentials for user "{self.username}"!') self.log(f'Invalid credentials for user "{self.username}"!')
raise InvalidCredentialsError raise InvalidCredentialsError
@ -39,11 +46,17 @@ class UserOps:
:raises UserExistsError: :raises UserExistsError:
A user with the provided username already exists A user with the provided username already exists
""" """
if self.db_session.query(User).filter(User.username == self.username).all(): existing_users = self.db_session.query(User).filter(
User.username == self.username
).all()
if existing_users:
raise UserExistsError raise UserExistsError
user = User(username=self.username, user = User(
passwordhash=PasswordHasher.hash(self.password)) username=self.username,
passwordhash=PasswordHasher.hash(self.password)
)
self.db_session.add(user) self.db_session.add(user)
self.db_session.commit() self.db_session.commit()