Exemplo n.º 1
0
    def user(self):
        """
        Load a related user from a database or similar. You might want to keep information about
        the current user and use this information across sessions, depending on your laboratory.
        Examples of this could be logs, or shared resources (e.g., storing the last actions of
        the user for the next time they log in). So as to load the user from the database, you
        can use :meth:`WebLab.user_loader` to define a user loader, and use this property to access
        later to it.

        For example, using `Flask-SQLAlchemy <http://flask-sqlalchemy.pocoo.org/>`_::

           from mylab.models import LaboratoryUser

           @weblab.on_start
           def start(client_data, server_data):
               # ...
               user = LaboratoryUser.query.filter(identifier.username_unique).first()
               if user is None:
                   # Make sure the user exists in the database
                   user_folder = create_user_folder()
                   user = LaboratoryUser(username=weblab_user.username,
                                     identifier=username_unique,
                                     user_folder=user_folder)
                   db.session.add(user)
                   db.session.commit()


           @weblab.user_loader
           def loader(username_unique):
               return LaboratoryUser.query.filter(identifier=username_unique).first()

           # And then later:

           @app.route('/lab')
           @requires_active
           def home():
               user_db = weblab_user.user
               open(os.path.join(user_db.user_folder, 'myfile.txt')).read()

           @app.route('/files')
           @requires_active
           def files():
               user_folder = weblab_user.user.user_folder
               # ...

        """
        user_loader = _current_weblab()._user_loader
        if user_loader is None:
            return None

        try:
            user = user_loader(self.username_unique)
        except:
            raise
        else:
            # Maybe in the future we should cache results so
            # no every weblab_user.user becomes a call to
            # the database? The main issue is with tasks or
            # long-standing processes
            return user
Exemplo n.º 2
0
 def wrapper(*args, **kwargs):
     if not weblab_user.active:
         if weblab_user.is_anonymous:
             # If anonymous user: forbidden
             return _current_weblab()._forbidden_handler()
         # Otherwise: if expired, just let it go
     return func(*args, **kwargs)
Exemplo n.º 3
0
 def wrapper(*args, **kwargs):
     if not weblab_user.active:
         if weblab_user.is_anonymous:
             # If anonymous user: forbidden
             return _current_weblab()._forbidden_handler()
         # If expired: send back to the original URL
         return redirect(weblab_user.back)
     return func(*args, **kwargs)
Exemplo n.º 4
0
def _current_task_stopping():
    task = _current_task()
    if not task:
        return False

    weblab = _current_weblab()
    updated_task_data = weblab._backend.get_task(task.task_id)
    if updated_task_data:
        return updated_task_data['stopping']

    return False
Exemplo n.º 5
0
def _current_task():
    task_id = getattr(g, '_weblab_task_id', None)
    if task_id is None:
        return None

    weblab_task = getattr(g, '_weblab_task', None)
    if weblab_task is None:
        weblab = _current_weblab()
        weblab_task = WebLabTask(weblab=weblab, task_id=task_id)
        g._weblab_task = weblab_task

    return weblab_task
Exemplo n.º 6
0
def dispose_user(session_id, waiting):
    backend = _current_backend()
    user = backend.get_user(session_id)
    if user.is_anonymous:
        raise NotFoundError()

    if isinstance(user, CurrentUser):
        current_expired_user = user.to_expired_user()
        deleted = backend.delete_user(session_id, current_expired_user)

        if deleted:
            try:
                weblab = _current_weblab()
                weblab._set_session_id(session_id)
                if weblab._on_dispose:

                    _set_weblab_user_cache(user)
                    try:
                        weblab._on_dispose()
                    except Exception:
                        traceback.print_exc()
                    update_weblab_user_data(response=None)
            finally:
                backend.finished_dispose(session_id)

            unfinished_tasks = backend.get_unfinished_tasks(session_id)
            for task_id in unfinished_tasks:
                unfinished_task = weblab.get_task(task_id)
                if unfinished_task:
                    unfinished_task.stop()

            while unfinished_tasks:
                unfinished_tasks = backend.get_unfinished_tasks(session_id)
                time.sleep(0.1)

            backend.clean_session_tasks(session_id)

            backend.report_session_deleted(session_id)

    if waiting:
        # if another thread has started the _dispose process, it might take long
        # to process it. But this (sessions) is the one that tells WebLab-Deusto
        # that someone else can enter in this laboratory. So we should wait
        # here until the process is over.

        while not backend.is_session_deleted(session_id):
            # In the future, instead of waiting, this could be returning that it is still finishing
            time.sleep(0.1)
Exemplo n.º 7
0
def status_time(session_id):
    weblab = _current_weblab()
    backend = weblab._backend
    user = backend.get_user(session_id)
    if isinstance(user, ExpiredUser) and user.disposing_resources:
        return 2  # Try again in 2 seconds

    if user.is_anonymous or not isinstance(user, CurrentUser):
        return -1

    if user.exited:
        return -1

    if weblab.timeout and weblab.timeout > 0:
        # If timeout is set to -1, it will never timeout (unless user exited)
        if user.time_without_polling >= weblab.timeout:
            return -1

    if user.time_left <= 0:
        return -1

    return min(weblab.poll_interval, int(user.time_left))
Exemplo n.º 8
0
def _process_start_request(request_data):
    """ Auxiliar method, called also from the Flask CLI to fake_user """
    client_initial_data = request_data['client_initial_data']
    server_initial_data = request_data['server_initial_data']

    # Parse the initial date + assigned time to know the maximum time
    start_date_timestamp = server_initial_data.get(
        'priority.queue.slot.start.timestamp')
    if start_date_timestamp:  # if the time is available in timestamp, use it
        start_date = datetime.datetime.fromtimestamp(
            float(start_date_timestamp))
    else:
        # Otherwise, to keep backwards compatibility, assume that it's in the same timezone
        # as we are
        start_date_str = server_initial_data['priority.queue.slot.start']
        start_date_str, microseconds = start_date_str.split('.')
        difference = datetime.timedelta(microseconds=int(microseconds))
        start_date = datetime.datetime.strptime(
            start_date_str, "%Y-%m-%d %H:%M:%S") + difference

    slot_length = float(server_initial_data['priority.queue.slot.length'])
    max_date = start_date + datetime.timedelta(seconds=slot_length)
    locale = server_initial_data.get('request.locale')
    full_name = server_initial_data['request.full_name']

    experiment_name = server_initial_data[
        'request.experiment_id.experiment_name']
    category_name = server_initial_data['request.experiment_id.category_name']
    experiment_id = '{}@{}'.format(experiment_name, category_name)

    # Create a global session
    session_id = create_token()

    # Prepare adding this to backend
    user = CurrentUser(
        session_id=session_id,
        back=request_data['back'],
        last_poll=_current_timestamp(),
        max_date=float(_to_timestamp(max_date)),
        username=server_initial_data['request.username'],
        username_unique=server_initial_data['request.username.unique'],
        exited=False,
        data={},
        locale=locale,
        full_name=full_name,
        experiment_name=experiment_name,
        experiment_id=experiment_id,
        category_name=category_name,
        request_client_data=client_initial_data,
        request_server_data=server_initial_data,
        start_date=float(_to_timestamp(start_date)))

    backend = _current_backend()

    backend.add_user(
        session_id,
        user,
        expiration=30 +
        int(float(server_initial_data['priority.queue.slot.length'])))

    kwargs = {}
    scheme = current_app.config.get(ConfigurationKeys.WEBLAB_SCHEME)
    if scheme:
        kwargs['_scheme'] = scheme

    weblab = _current_weblab()
    if weblab._on_start:
        _set_weblab_user_cache(user)
        weblab._set_session_id(session_id)
        try:
            data = weblab._on_start(client_initial_data, server_initial_data)
        except Exception as error:
            traceback.print_exc()
            current_app.logger.warning(
                "Error calling _on_start: {}".format(error), exc_info=True)
            try:
                dispose_user(session_id, waiting=True)
            except Exception as nested_error:
                traceback.print_exc()
                current_app.logger.warning(
                    "Error calling _on_dispose after _on_start failed: {}".
                    format(nested_error),
                    exc_info=True)

            return dict(error=True, message="Error initializing laboratory")
        else:
            if data:
                user.data = data
            user.data.store_if_modified()
            update_weblab_user_data(response=None)

    link = url_for('weblab_callback_url',
                   session_id=session_id,
                   _external=True,
                   **kwargs)
    return dict(url=link, session_id=session_id)