mirror of
				https://github.com/avatao-content/test-tutorial-framework
				synced 2025-11-04 02:42:56 +00:00 
			
		
		
		
	Merge branch 'ocicat', the unrealized dream. Ocicat will return...
This commit is contained in:
		@@ -7,9 +7,9 @@ RUN pip3 install Flask==1.0        \
 | 
			
		||||
                 git+https://github.com/avatao-content/tfwconnector.git#subdirectory=python3
 | 
			
		||||
 | 
			
		||||
# Define variables to use later
 | 
			
		||||
ENV TFW_EHMAIN_DIR="/srv/.tfw_builtin_ehs"          \
 | 
			
		||||
    TFW_WEBSERVICE_DIR="/srv/webservice"            \
 | 
			
		||||
    TFW_IDE_WD="/home/${AVATAO_USER}/workdir"       \
 | 
			
		||||
ENV TFW_EHMAIN_DIR="${TFW_DIR}/builtin_event_handlers" \
 | 
			
		||||
    TFW_WEBSERVICE_DIR="/srv/webservice"               \
 | 
			
		||||
    TFW_IDE_WD="/home/${AVATAO_USER}/workdir"          \
 | 
			
		||||
    TFW_TERMINADO_WD="/home/${AVATAO_USER}/workdir"
 | 
			
		||||
 | 
			
		||||
# Copy TFW related stuff to a dedicated directory
 | 
			
		||||
@@ -26,7 +26,8 @@ RUN mkdir -p ${TFW_IDE_WD}                                               &&\
 | 
			
		||||
    chmod -R 755 "${TFW_IDE_WD}" "${TFW_WEBSERVICE_DIR}"
 | 
			
		||||
 | 
			
		||||
# Hide TFW related code from user
 | 
			
		||||
RUN chown -R root:root ${TFW_SERVER_DIR} && chmod -R 700 ${TFW_SERVER_DIR}
 | 
			
		||||
RUN chown -R root:root ${TFW_SERVER_DIR} ${TFW_DIR} &&\
 | 
			
		||||
    chmod -R 700 ${TFW_SERVER_DIR} ${TFW_DIR}
 | 
			
		||||
 | 
			
		||||
# Make AVATAO_USER's home writeable and set it as WORKDIR
 | 
			
		||||
# Make webservice directory writable
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,12 @@ from signal import signal, SIGTERM, SIGINT
 | 
			
		||||
 | 
			
		||||
from tornado.ioloop import IOLoop
 | 
			
		||||
 | 
			
		||||
from tfw import YamlFSM, FSMAwareEventHandler, EventHandlerBase
 | 
			
		||||
from tfw.fsm import YamlFSM
 | 
			
		||||
from tfw.event_handler_base import EventHandlerBase, FSMAwareEventHandler
 | 
			
		||||
from tfw.components import IdeEventHandler, TerminalEventHandler
 | 
			
		||||
from tfw.components import ProcessManagingEventHandler, BashMonitor
 | 
			
		||||
from tfw.components import TerminalCommands, LogMonitoringEventHandler
 | 
			
		||||
from tfw.components import FSMManagingEventHandler
 | 
			
		||||
from tfw.components import FSMManagingEventHandler, DirectorySnapshottingEventHandler
 | 
			
		||||
from tfw.networking import MessageSender, TFWServerConnector
 | 
			
		||||
from tfw.config import TFWENV
 | 
			
		||||
from tfw.config.logs import logging
 | 
			
		||||
@@ -87,22 +88,29 @@ class MessageFSMStepsEventHandler(FSMAwareEventHandler):
 | 
			
		||||
    def handle_event(self, message):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def handle_fsm_step(self, from_state, to_state, trigger):
 | 
			
		||||
    def handle_fsm_step(self, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
        When the FSM steps this method is invoked.
 | 
			
		||||
        Receives a 'data' field from an fsm_update message as kwargs.
 | 
			
		||||
        """
 | 
			
		||||
        MessageSender().send(
 | 
			
		||||
            'FSM info',
 | 
			
		||||
            f'FSM has stepped from state "{from_state}" '
 | 
			
		||||
            f'to state "{to_state}" in response to trigger "{trigger}"'
 | 
			
		||||
            f'FSM has stepped from state "{kwargs["last_event"]["from_state"]}" '
 | 
			
		||||
            f'to state "{kwargs["current_state"]}" in response to trigger "{kwargs["last_event"]["trigger"]}"'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
def main():
 | 
			
		||||
    # pylint: disable=unused-variable
 | 
			
		||||
    #
 | 
			
		||||
    # TFW component EventHandlers (builtins, required for their respective functionalities)
 | 
			
		||||
    fsm = FSMManagingEventHandler( # TFW FSM
 | 
			
		||||
    fsm = FSMManagingEventHandler(  # TFW FSM
 | 
			
		||||
        key='fsm',
 | 
			
		||||
        fsm_type=partial(YamlFSM, 'test_fsm.yml')
 | 
			
		||||
        fsm_type=partial(
 | 
			
		||||
            YamlFSM,
 | 
			
		||||
            'test_fsm.yml',
 | 
			
		||||
            {}  # jinja2 variables, use empty dict to enable jinja2 parsing without any variables
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    ide = IdeEventHandler(  # Web IDE backend
 | 
			
		||||
        key='ide',
 | 
			
		||||
@@ -124,17 +132,22 @@ if __name__ == '__main__':
 | 
			
		||||
        process_name='webservice',
 | 
			
		||||
        log_tail=2000
 | 
			
		||||
    )
 | 
			
		||||
    snapshot = DirectorySnapshottingEventHandler(  # Manages filesystem snapshots of directories
 | 
			
		||||
        key='snapshot',
 | 
			
		||||
        directories=[
 | 
			
		||||
            TFWENV.IDE_WD,
 | 
			
		||||
            TFWENV.WEBSERVICE_DIR
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Your custom event handlers
 | 
			
		||||
    message_fsm_steps = MessageFSMStepsEventHandler(
 | 
			
		||||
    message_fsm_steps_eh = MessageFSMStepsEventHandler(
 | 
			
		||||
        key='test'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Terminal command handlers
 | 
			
		||||
    commands = TestCommands(bashrc=f'/home/{TAOENV.USER}/.bashrc')
 | 
			
		||||
    terminal.historymonitor.subscribe_callback(commands.callback)
 | 
			
		||||
 | 
			
		||||
    # Example terminal command callback
 | 
			
		||||
    terminal.historymonitor.subscribe_callback(cenator)
 | 
			
		||||
 | 
			
		||||
    event_handlers = EventHandlerBase.get_local_instances()
 | 
			
		||||
@@ -146,3 +159,7 @@ if __name__ == '__main__':
 | 
			
		||||
    signal(SIGINT, cleanup)
 | 
			
		||||
 | 
			
		||||
    IOLoop.instance().start()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ from signal import signal, SIGTERM, SIGINT
 | 
			
		||||
 | 
			
		||||
from tornado.ioloop import IOLoop
 | 
			
		||||
 | 
			
		||||
from tfw import EventHandlerBase
 | 
			
		||||
from tfw.event_handler_base import EventHandlerBase
 | 
			
		||||
from tfw.components import PipeIOEventHandler
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
from os.path import exists
 | 
			
		||||
 | 
			
		||||
from tfw import LinearFSM
 | 
			
		||||
from tfw.fsm import LinearFSM
 | 
			
		||||
from tfw.networking import MessageSender
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,3 +41,8 @@ transitions:
 | 
			
		||||
    -   trigger: step_5
 | 
			
		||||
        source: '4'
 | 
			
		||||
        dest: '5'
 | 
			
		||||
    {% for i in range(5) %}     # you can also use jinja2 in this config file
 | 
			
		||||
    -   trigger: 'step_next'
 | 
			
		||||
        source: '{{i}}'
 | 
			
		||||
        dest: '{{i+1}}'
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,18 +13,29 @@ session_factory = sessionmaker(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@contextmanager
 | 
			
		||||
def Session(factory=session_factory):
 | 
			
		||||
    session = factory()
 | 
			
		||||
    try:
 | 
			
		||||
        yield session
 | 
			
		||||
        session.commit()
 | 
			
		||||
    except:
 | 
			
		||||
        session.rollback()
 | 
			
		||||
        raise
 | 
			
		||||
    # session is closed by flask
 | 
			
		||||
    # finally:
 | 
			
		||||
    #     session.close()
 | 
			
		||||
class SessionWrapper:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self._session_factory = session_factory
 | 
			
		||||
        self._session_handle = None
 | 
			
		||||
 | 
			
		||||
    @contextmanager
 | 
			
		||||
    def session(self):
 | 
			
		||||
        try:
 | 
			
		||||
            yield self._session
 | 
			
		||||
            self._session.commit()
 | 
			
		||||
        except:
 | 
			
		||||
            self._session.rollback()
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def _session(self):
 | 
			
		||||
        if self._session_handle is None:
 | 
			
		||||
            self._session_handle = self._session_factory()
 | 
			
		||||
        return self._session_handle
 | 
			
		||||
 | 
			
		||||
    def teardown(self):
 | 
			
		||||
        if self._session_handle is not None:
 | 
			
		||||
            self._session_handle.close()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Base = declarative_base()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,8 @@
 | 
			
		||||
from os import urandom, getenv
 | 
			
		||||
from functools import partial
 | 
			
		||||
 | 
			
		||||
from flask import Flask, render_template, request, session, url_for, g
 | 
			
		||||
 | 
			
		||||
from model import init_db, session_factory, Session
 | 
			
		||||
from model import init_db, SessionWrapper
 | 
			
		||||
from user_ops import UserOps
 | 
			
		||||
from errors import InvalidCredentialsError, UserExistsError
 | 
			
		||||
 | 
			
		||||
@@ -16,25 +15,24 @@ app.jinja_env.globals.update(  # pylint: disable=no-member
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_db_session():
 | 
			
		||||
    if not hasattr(g, 'db_session'):
 | 
			
		||||
        g.db_session = session_factory()
 | 
			
		||||
    return g.db_session
 | 
			
		||||
 | 
			
		||||
Session = partial(Session, get_db_session)
 | 
			
		||||
@app.before_request
 | 
			
		||||
def setup_db():
 | 
			
		||||
    # pylint: disable=protected-access
 | 
			
		||||
    g._db_session_wrapper = SessionWrapper()
 | 
			
		||||
    g.db_session = g._db_session_wrapper.session
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.teardown_appcontext
 | 
			
		||||
def close_db_session(err): # pylint: disable=unused-argument
 | 
			
		||||
    if hasattr(g, 'db_session'):
 | 
			
		||||
        g.db_session.close()
 | 
			
		||||
def close_db_session(_):
 | 
			
		||||
    # pylint: disable=protected-access
 | 
			
		||||
    g._db_session_wrapper.teardown()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/', methods=['GET', 'POST'])
 | 
			
		||||
def index():
 | 
			
		||||
    if request.method == 'POST':
 | 
			
		||||
        try:
 | 
			
		||||
            with Session() as db_session:
 | 
			
		||||
            with g.db_session() as db_session:
 | 
			
		||||
                UserOps(
 | 
			
		||||
                    request.form.get('username'),
 | 
			
		||||
                    request.form.get('password'),
 | 
			
		||||
@@ -67,7 +65,7 @@ def register():
 | 
			
		||||
            return render_template('register.html', alert='Passwords do not match! Please try again.')
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            with Session() as db_session:
 | 
			
		||||
            with g.db_session() as db_session:
 | 
			
		||||
                UserOps(
 | 
			
		||||
                    request.form.get('username'),
 | 
			
		||||
                    request.form.get('password'),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user