diff --git a/.devcontainer/Dockerfile.dev b/.devcontainer/Dockerfile.dev index 80a45f6f7..dc75fa13d 100644 --- a/.devcontainer/Dockerfile.dev +++ b/.devcontainer/Dockerfile.dev @@ -45,10 +45,12 @@ ENV PIP_BREAK_SYSTEM_PACKAGES 1 USER root RUN apt-get update && apt-get install -y python3 python3-pip python3-dev pkg-config default-libmysqlclient-dev \ libpcre3-dev -# Create a dummy secret -COPY < "/etc/discourse/client-api-key"' - pip3 install -e .[dev,test] + pip3 install .[dev,test] make setup + env: + TIRA_ROOT: ${{github.workspace}}/model/src + TIRA_CONFIG: ${{github.workspace}}/application/config/tira-application-config.yml + DISCOURSE_API_KEY: "I am so secret" - name: Run backend tests working-directory: ${{github.workspace}}/application/test run: pytest diff --git a/README.md b/README.md index b2624219d..b0a329d5f 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Deployment - - Tests + + Tests Linters diff --git a/application/.devcontainer.json b/application/.devcontainer.json deleted file mode 100644 index 99ded8ed7..000000000 --- a/application/.devcontainer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "image": "webis/tira-application:basis-0.0.96", - "customizations": { - "vscode": { - "extensions": ["ms-python.python", "ms-python.vscode-pylance", "ms-toolsai.jupyter"] - } - } -} diff --git a/application/.dockerignore b/application/.dockerignore index f83a4abb6..bac451f72 100644 --- a/application/.dockerignore +++ b/application/.dockerignore @@ -1,2 +1,303 @@ +mock-data + +.dockerignore +.gitignore +Dockerfile.* +Makefile +README.md + +test/tira-root +.data-dumps + + +# Gitignore contentn +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +#build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ venv/ -**/node_modules/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. + .idea/artifacts + .idea/compiler.xml + .idea/jarRepositories.xml + .idea/modules.xml + .idea/*.iml + .idea/modules + *.iml + *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser +tira.iml + +### Eclipse ### +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + +### Eclipse Patch ### +# Spring Boot Tooling +.sts4-cache/ + +# End of https://www.toptal.com/developers/gitignore/api/eclipse + +/bin/ +conf/disraptor.properties +*.swp +/info/ +tira-web/tira-web/lib/ + +# Mac +.DS_Store + +# TextMate +frontend/.editorconfig + diff --git a/application/.gitignore b/application/.gitignore index ef5a5d0ce..117dbbb48 100644 --- a/application/.gitignore +++ b/application/.gitignore @@ -3,13 +3,11 @@ src/tira_vm_states.sqlite3 src/venv src/__init__.py src/config -src/tira/migrations/*.py +src/tira_app/migrations/*.py test/test-database -src/tira/frontend/node_modules/ -src/tira/static/tira/dist/* +src/tira_app/static/tira/dist/* package-lock.json -src/tira/frontend/webpack-stats.json test/tira-root/ **/*.received.txt diff --git a/application/Dockerfile.application b/application/Dockerfile.application index bea1a11e5..d0140e093 100644 --- a/application/Dockerfile.application +++ b/application/Dockerfile.application @@ -1,13 +1,3 @@ -#Build Vuetify in first stage: Only change in case of new / updated dependencies -FROM webis/tira-application:basis-0.0.97 - -COPY frontend /src/tira/frontend-vuetify - -RUN cd /src/tira/frontend-vuetify \ - && ln -s /usr/local/lib/node_modules node_modules \ - && yarn build - - # Only change in case of new / updated dependencies FROM webis/tira-application:basis-0.0.96 @@ -27,9 +17,6 @@ RUN cd /tira/application/src && \ chmod +x /tira/application/src/tira/endpoints/aha && \ cp /tira/application/src/tira/management/commands/irds_cli.sh /irds_cli.sh && \ rm -f ./config/settings.yml ./config/config.yml ./config/tira-application-config.dev.yml && \ - rm -Rf tira/static/tira/frontend-vuetify/ && rm -Rf /tira/application/src/tira/static/tira/frontend-vuetify/ - -COPY --from=0 /src/tira/static/tira/frontend-vuetify/ /tira/application/src/tira/static/tira/frontend-vuetify/ RUN cd /tira/application/ && \ ./test/run_all_tests.sh diff --git a/application/Dockerfile.prod b/application/Dockerfile.prod new file mode 100644 index 000000000..c9fd9e723 --- /dev/null +++ b/application/Dockerfile.prod @@ -0,0 +1,126 @@ +# TODO: this dockerfile is the latest and greatest out of the large quantity found in this folder +# At some point, Dockerfile.application* and Dockerfile.basis should be obsolete and can be deleted. If you read this in +# the future and that is the case, then "Hello Future Person" and also please delete these dockerfiles. + +# !!! This Dockerfile needs to be build from the project root and NOT the application folder !!! + +######################################################################################################################## +# Build Container # +######################################################################################################################## +FROM debian:stable-slim AS build + +ENV TZ=Europe/Berlin +RUN < /etc/timezone +apt-get -qq update && apt-get -qq install -y locales +echo "en_US.UTF-8 UTF-8" | tee -a /etc/locale.gen && locale-gen +EOF + +######################################################################################################################## +# Create User # +######################################################################################################################## +RUN useradd -ms /bin/bash tira + +######################################################################################################################## +# Copy all neccessary files over # +######################################################################################################################## +USER tira +WORKDIR /tira/ +COPY --chown=tira:tira ./application ./ +COPY --chown=tira:tira ./python-client ../python-client + +######################################################################################################################## +# Install Python and Dependencies # +######################################################################################################################## +USER root +ENV PIP_BREAK_SYSTEM_PACKAGES=1 +# For faster build of GRPCIO (TODO: remove when GRPC is not used anymore) +ENV GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=16 + +RUN < /etc/timezone +apt-get -qq update && apt-get -qq install -y locales +echo "en_US.UTF-8 UTF-8" | tee -a /etc/locale.gen && locale-gen + +# Tools +apt-get -qq install -y python3 python3-dev +# For MariaDB +apt-get -qq install -y mariadb-client +# +mkdir -p /tira/application/src +chown -R tira:tira /tira +EOF + + +######################################################################################################################## +# Copy Data & Install Python and Dependencies # +######################################################################################################################## +COPY --from=build --chown=tira:tira /tira/src/manage.py /home/tira/manage.py + +RUN <.zip django-db-dump.zip If there are problems with the precompiled protobuf parser, you can recompile them from the `tira/protocol` repository and copy them to `tira/application/src/tira/proto`. If you run into `django.db.utils.OperationalError: (1050, "Table already exists")`, skip migrations using `./venv/bin/python3 src/manage.py migrate --fake` . - -Windows users using WSL: If you run into `setup.sh: line 3: $'\r'`: command not found' when executing make setup: - 1. run `sudo apt-get install dos2unix` - 2. run `dos2unix setup.sh` - 3. run `cd tests && dos2unix setup.sh` - 4. Now make setup should work - - Error running vite-dev: `00h00m00s 0/0: : ERROR: [Errno 2] No such file or directory: 'install'`: - run `apt remove cmdtest - sudo apt remove yarn - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list - sudo apt-get update - sudo apt-get install yarn -y` diff --git a/application/config/tira-application-config.dev.yml b/application/config/tira-application-config.dev.yml deleted file mode 100644 index b95863633..000000000 --- a/application/config/tira-application-config.dev.yml +++ /dev/null @@ -1,26 +0,0 @@ -# ---task/celebrity-profiling/user/hodge20a -debug: true -allowed_hosts: - - "127.0.0.1" -django_secret: 'not-so-secret' -# --- -# tira_root: /mnt/ceph/tira -# deployment = {disraptor} -# TODO: remove deployment configuration key -deployment: disraptor -disraptor_secret_file: /etc/discourse/client-api-key -# The directory where logs are written to. Defaults to TIRA_ROOT/log/tira-application -# logging_dir: /mnt/ceph/tira/log/tira-application -# grpc_host can be local or remote. If local, it will call localhost (i.e. for testing). If remote, it will call the vm-host -# When developing, set this option to local, otherwise you might accidentally remote-control the live-vms. -grpc_host: local -host_grpc_port: 50051 -application_grpc_port: 50052 -database: - engine: django.db.backends.sqlite3 # django.db.backends.mysql or django.db.backends.sqlite3 - name: tira # when backend is sqlite, this will be the name of the database below TIRA_ROOT/state - user: tira # ignored when using sqlite3 - password: TODO-ENTER-PASSWORD # ignored when using sqlite3 - host: tira-mariadb # ignored when using sqlite3 - port: 3306 # ignored when using sqlite3 -github_token: TODO-ENTER-TOKEN diff --git a/application/config/tira-application-config.docker.yml b/application/config/tira-application-config.docker.yml deleted file mode 100644 index 9f13b3ccc..000000000 --- a/application/config/tira-application-config.docker.yml +++ /dev/null @@ -1,25 +0,0 @@ -# ---task/celebrity-profiling/user/hodge20a -debug: true -allowed_hosts: - - "127.0.0.1" -django_secret: 'not-so-secret' -# --- -# tira_root: /mnt/ceph/tira -# deployment = {disraptor} -deployment: disraptor -# disraptor_secret_file: /etc/discourse/client-api-key -# The directory where logs are written to. Defaults to TIRA_ROOT/log/tira-application -# logging_dir: /mnt/ceph/tira/log/tira-application -# grpc_host can be local or remote. If local, it will call localhost (i.e. for testing). If remote, it will call the vm-host -# When developing, set this option to local, otherwise you might accidentally remote-control the live-vms. -grpc_host: local -host_grpc_port: 50051 -application_grpc_port: 50052 -database: - engine: django.db.backends.sqlite3 # django.db.backends.mysql or django.db.backends.sqlite3 - name: tira # when backend is sqlite, this will be the name of the database below TIRA_ROOT/state - user: tira # ignored when using sqlite3 - password: TODO-ENTER-PASSWORD # ignored when using sqlite3 - host: tira-mariadb # ignored when using sqlite3 - port: 3306 # ignored when using sqlite3 - diff --git a/application/config/tira-application-config.yml b/application/config/tira-application-config.yml new file mode 100644 index 000000000..bdb93a62c --- /dev/null +++ b/application/config/tira-application-config.yml @@ -0,0 +1,61 @@ +# For your convenience, we marked secrets with [SECRET]. Make sure, you change these +# values from their defaults! + +########################################################################################## +# TIRA # +########################################################################################## +# Enables debug mode. This means more verbose output in the console and for the REST-API. +# Settings this value to true in production is a security risk! +debug: !ENV ${TIRA_DEBUG:false} + +tira_root: !ENV ${TIRA_ROOT:/tira} +# The directory where logs are written to. Defaults to TIRA_ROOT/log/tira-application +# logging_dir: /mnt/ceph/tira/log/tira-application + +# [SECRET] +github_token: !ENV ${TIRA_GITHUB_TOKEN} + +########################################################################################## +# Database # +########################################################################################## +database: + # django.db.backends.mysql or django.db.backends.sqlite3 + engine: !ENV ${TIRA_DB_ENGINE:django.db.backends.sqlite3} + # when backend is sqlite, this will be the name of the database below TIRA_ROOT/state + name: !ENV ${TIRA_DB_NAME:tira} + user: !ENV ${TIRA_DB_USER:tira} # ignored when using sqlite3 + password: !ENV ${TIRA_DB_PASSWORD} # ignored when using sqlite3 + host: !ENV ${TIRA_DB_HOST:tira-mariadb} # ignored when using sqlite3 + port: !ENV ${TIRA_DB_PORT:3306} # ignored when using sqlite3 + +########################################################################################## +# Discourse # +########################################################################################## +discourse_api_url: !ENV ${DISCOURSE_API_URL:https://www.tira.io} + +# [SECRET] +discourse_api_key: !ENV ${DISCOURSE_API_KEY:""} + +########################################################################################## +# Django # +########################################################################################## +# A list of hostnames using which the backend may be addressed. The value "*" denotes any +# address. A value of ["tira.example.com", "example.com"] would only allow requests made +# addressing these hostnames. See +# https://docs.djangoproject.com/en/5.1/ref/settings/#allowed-hosts for more information. +allowed_hosts: + - "*" + +# [SECRET] See https://docs.djangoproject.com/en/5.1/ref/settings/#std-setting-SECRET_KEY +# for more information. +django_secret: !ENV ${DJANGO_SECRET:change-me!} + +########################################################################################## +# Deprecated and removed soon (we hope) # +########################################################################################## +# grpc_host can be local or remote. If local, it will call localhost (i.e., for testing). +# If remote, it will call the vm-host. When developing, set this option to local, +# otherwise you might accidentally remote-control the live-vms. +grpc_host: local +host_grpc_port: 50051 +application_grpc_port: 50052 diff --git a/application/pyproject.toml b/application/pyproject.toml index 30388f6b4..d3de6c31c 100644 --- a/application/pyproject.toml +++ b/application/pyproject.toml @@ -1,8 +1,8 @@ [tool.black] line-length = 120 exclude = '''/( - src/tira/migrations - | src/tira/proto + src/tira_app/migrations + | src/tira_app/proto )''' [tool.isort] @@ -11,8 +11,8 @@ multi_line_output = 3 line_length = 120 include_trailing_comma = true skip = [ - "src/tira/migrations", - "src/tira/proto", + "src/tira_app/migrations", + "src/tira_app/proto", ] [tool.mypy] @@ -21,8 +21,8 @@ explicit_package_bases = true ignore_missing_imports = true install_types = true exclude = [ - "^src/tira/proto/.*\\.py$", - "^src/tira/migrations/.*\\.py$", + "^src/tira_app/proto/.*\\.py$", + "^src/tira_app/migrations/.*\\.py$", ] [tool.pytest.ini_options] @@ -31,4 +31,13 @@ pythonpath = ["./src", "./test"] python_files = "test_*.py" [tool.pytest_env] -HF_HOME = "./tira-root/huggingface" \ No newline at end of file +HF_HOME = "./tira-root/huggingface" +TIRA_ROOT = "./tira-root" +TIRA_CONFIG = "../config/tira-application-config.yml" +TIRA_DEBUG = true +TIRA_DB_ENGINE = "django.db.backends.sqlite3" +TIRA_DB_NAME = "test-database/sqlite3" +TIRA_DB_USER = "tira" +TIRA_DB_PASSWORD = "replace-with-db-password" +TIRA_DB_HOST = "tira-mariadb" +TIRA_DB_PORT = 3306 diff --git a/application/setup.cfg b/application/setup.cfg index 8ed7f4738..755f27756 100644 --- a/application/setup.cfg +++ b/application/setup.cfg @@ -1,37 +1,38 @@ +[metadata] +name = tira_app [options] python_requires = >=3.9 include_package_data = True -packages = find: +package_dir = + = src +packages = find_namespace: install_requires = grpcio>=1.53.2 # grpcio-tools==1.36.1 # still needed? protobuf<4.0dev - pyuwsgi - Django + Django==5.0.9 pyyaml requests randomname tqdm - mysql mysqlclient - django-webpack-loader==0.6.0 - python-gitlab + python-gitlab==4.10.0 GitPython python-slugify - ir-datasets@git+https://github.com/allenai/ir_datasets + ir-datasets diffir@git+https://github.com/mam10eks/diffir pandas markdown PyGithub==1.59.1 - ghapi django-extensions discourse-client-in-disraptor==0.0.8 - tira>=0.0.97 + # tira>=0.0.97 huggingface-hub djangorestframework==3.15.1 django-filter==24.2 djangorestframework-jsonapi==7.0.0 + pyaml-env==1.2.1 [options.extras_require] test = @@ -47,7 +48,20 @@ dev = flake8 isort mypy +deploy = + uwsgi +postgreqsql = + psycopg2-binary +[options.packages.find] +where = src +include = + tira_app + tira_app.* + django_admin + +[options.package_data] +tira_app.res = *.yml [flake8] max-line-length = 120 diff --git a/application/setup.py b/application/setup.py new file mode 100644 index 000000000..606849326 --- /dev/null +++ b/application/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup() diff --git a/application/setup.sh b/application/setup.sh deleted file mode 100755 index c26eaba97..000000000 --- a/application/setup.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# setup.sh does steps in the tira setup. - -exit_with () { - echo $1 - echo "Exiting setup.sh; Please install the required software."; - exit 1 -} - -which mysql_config > '\dev\null' || exit_with "Please install the sql driver before the tira-application setup: - sudo apt install libmysqlclient-dev - sudo apk add mariadb-dev" - -which npm > '\dev\null' || exit_with "Please install npm to build the vue frontend - https://nodejs.org/en/download/" diff --git a/application/src/django_admin/settings.py b/application/src/django_admin/settings.py index c7e192fba..491d7be0e 100644 --- a/application/src/django_admin/settings.py +++ b/application/src/django_admin/settings.py @@ -10,57 +10,62 @@ https://docs.djangoproject.com/en/3.1/ref/settings/ """ +import importlib.resources as resources import logging import os from pathlib import Path import yaml +from pyaml_env import parse_config + +from tira_app.util import str2bool # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent custom_settings = {} -for cfg in (BASE_DIR / "config").glob("*.yml"): - print(f"Load settings from {cfg}.") - custom_settings.update(yaml.load(open(cfg, "r").read(), Loader=yaml.FullLoader)) +cfgpath = os.environ.get("TIRA_CONFIG", str(BASE_DIR / "config" / "tira-application-config.yml")) +logging.info(f"Load settings from {cfgpath}.") +config = parse_config(cfgpath, default_value=None, loader=yaml.FullLoader) +custom_settings.update(config) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = str2bool(custom_settings["debug"]) -if "database" not in custom_settings: - custom_settings["database"] = {} +if DEBUG: + logging.basicConfig(level=logging.DEBUG, force=True) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = custom_settings.get("django_secret", "not-so-secret") +# https://docs.djangoproject.com/en/5.1/ref/settings/#std-setting-SECRET_KEY +SECRET_KEY = custom_settings["django_secret"] -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = custom_settings.get("debug", True) -ALLOWED_HOSTS = custom_settings.get("allowed_hosts", []) +ALLOWED_HOSTS = custom_settings["allowed_hosts"] -TIRA_ROOT = Path(custom_settings.get("tira_root", BASE_DIR.parents[1] / "model" / "src")) +TIRA_ROOT = Path(custom_settings["tira_root"]) if not TIRA_ROOT.is_dir(): logging.warning(f"{TIRA_ROOT} does not exists and will be created now.") (TIRA_ROOT / "state").mkdir(parents=True, exist_ok=True) -DEPLOYMENT = custom_settings.get("deployment", "disraptor") -DISRAPTOR_SECRET_FILE = Path(custom_settings.get("disraptor_secret_file", "/etc/discourse/client-api-key")) HOST_GRPC_PORT = custom_settings.get("host_grpc_port", "50051") APPLICATION_GRPC_PORT = custom_settings.get("application_grpc_port", "50052") GRPC_HOST = custom_settings.get("grpc_host", "local") # can be local or remote TIRA_DB_NAME = ( - Path(TIRA_ROOT / "state") / f"{custom_settings['database'].get('name', 'tira')}.sqlite3" - if custom_settings["database"].get("engine", "django.db.backends.sqlite3") == "django.db.backends.sqlite3" - else custom_settings["database"].get("name", "tira") + Path(TIRA_ROOT / "state") / f"{custom_settings['database']['name']}.sqlite3" + if custom_settings["database"]["engine"] == "django.db.backends.sqlite3" + else custom_settings["database"]["name"] ) TIRA_DB = { - "ENGINE": custom_settings["database"].get("engine", "django.db.backends.sqlite3"), + "ENGINE": custom_settings["database"]["engine"], "NAME": TIRA_DB_NAME, - "USER": custom_settings["database"].get("user", "tira"), - "PASSWORD": custom_settings["database"].get("password", "replace-with-db-password"), - "HOST": custom_settings["database"].get("host", "tira-mariadb"), - "PORT": int(custom_settings["database"].get("port", 3306)), + "USER": custom_settings["database"]["user"], + "PASSWORD": custom_settings["database"]["password"], + "HOST": custom_settings["database"]["host"], + "PORT": int(custom_settings["database"]["port"]), "TEST": { "NAME": "test_tira", "ENGINE": "django.db.backends.sqlite3", @@ -69,7 +74,7 @@ # Application definition INSTALLED_APPS = [ - "tira.apps.TiraConfig", + "tira_app.apps.TiraConfig", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", @@ -77,7 +82,6 @@ "django_filters", "rest_framework", "rest_framework_json_api", - "webpack_loader", ] MIDDLEWARE = [ @@ -91,8 +95,9 @@ ] REST_FRAMEWORK = { - "DEFAULT_AUTHENTICATION_CLASSES": ("tira.authentication.TrustedHeaderAuthentication",), + "DEFAULT_AUTHENTICATION_CLASSES": ("tira_app.authentication.TrustedHeaderAuthentication",), "DEFAULT_FILTER_BACKENDS": ("rest_framework_json_api.django_filters.DjangoFilterBackend",), + "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",), } ROOT_URLCONF = "django_admin.urls" @@ -324,7 +329,7 @@ def logger_config(log_dir: Path): ' ${inputDataset}/qrels.txt --output ${outputDir} --measures "P@10" "nDCG@10" "MRR"', ) -GITHUB_TOKEN = custom_settings.get("github_token", "") +GITHUB_TOKEN = custom_settings["github_token"] # Caching CACHES = { @@ -336,8 +341,9 @@ def logger_config(log_dir: Path): } } -# FIXME: I don't close my file handle :(((((((( -TIREX_COMPONENTS = yaml.load(open(BASE_DIR / "tirex-components.yml").read(), Loader=yaml.FullLoader) +TIREX_COMPONENTS = yaml.load( + (resources.files("tira_app.res") / "tirex-components.yml").read_bytes(), Loader=yaml.FullLoader +) # Logging ld = Path(custom_settings.get("logging_dir", TIRA_ROOT / "log" / "tira-application")) @@ -356,24 +362,6 @@ def logger_config(log_dir: Path): raise PermissionError(f"Can not write to {ld} in production mode.") -# Password validation -# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ @@ -387,15 +375,8 @@ def logger_config(log_dir: Path): USE_TZ = True -WEBPACK_LOADER = { - "DEFAULT": { - "CACHE": DEBUG, - "BUNDLE_DIR_NAME": "/bundles/", - "STATS_FILE": BASE_DIR / "tira" / "frontend" / "webpack-stats.json", - } -} - -DISCOURSE_API_URL = "https://www.tira.io" +DISCOURSE_API_URL = custom_settings["discourse_api_url"] +DISRAPTOR_API_KEY = custom_settings["discourse_api_key"] PUBLIC_TRAINING_DATA = set(["jena-topics-20231026-test", "leipzig-topics-20231025-test"]) CODE_SUBMISSION_REFERENCE_REPOSITORIES = { @@ -418,7 +399,3 @@ def logger_config(log_dir: Path): } CODE_SUBMISSION_REPOSITORY_NAMESPACE = "tira-io" -try: - DISRAPTOR_API_KEY = open(DISRAPTOR_SECRET_FILE, "r").read().strip() -except Exception: - pass diff --git a/application/src/django_admin/urls.py b/application/src/django_admin/urls.py index fb5bb717f..02850af19 100644 --- a/application/src/django_admin/urls.py +++ b/application/src/django_admin/urls.py @@ -17,5 +17,5 @@ from django.urls import include, path urlpatterns = [ - path("", include("tira.urls")), + path("", include("tira_app.urls")), ] diff --git a/application/src/django_admin/wsgi.py b/application/src/django_admin/wsgi.py index ed2789c32..f473d6bc5 100644 --- a/application/src/django_admin/wsgi.py +++ b/application/src/django_admin/wsgi.py @@ -9,8 +9,12 @@ import os +from django.core.management import call_command from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_admin.settings") application = get_wsgi_application() + +# https://stackoverflow.com/a/58182766 +call_command("migrate") diff --git a/application/src/run_grpc_server.py b/application/src/run_grpc_server.py index de9d3b581..b1aa43ddd 100644 --- a/application/src/run_grpc_server.py +++ b/application/src/run_grpc_server.py @@ -2,7 +2,7 @@ import django -from tira.grpc import grpc_server +from tira_app.grpc import grpc_server os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_admin.settings") diff --git a/application/src/tira/static/tira/css/tira-style.css b/application/src/tira/static/tira/css/tira-style.css deleted file mode 100644 index 7adacc84e..000000000 --- a/application/src/tira/static/tira/css/tira-style.css +++ /dev/null @@ -1,147 +0,0 @@ -.index-main-cover { - background: #323232 url("../img/background2.jpg") no-repeat top right; - background-size: 100%; - height: 250px; - width: 100%; - min-height: 200px; - font-size: 1.05rem; -} - -.index-main-cover h1 { - font-size: 2.65rem -} - -.cover-background-fade { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: linear-gradient(to bottom, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 40%, rgba(0, 0, 0, 0.85) 85%) -} - -.dataset-detail-icon { - height: 15px; - width: 15px; - min-width: 20px; - min-height: 20px; -} - -.dropdown-scroll { - /*height: auto;*/ - max-height: calc(100vh - 52ex); - overflow-x: auto; - overflow-y: visible; -} - -.scrollable-table { - overflow-x: visible; - overflow-y: hidden; -} - -a.uk-button-primary { - color: #fff; -} - -.tira-content label { - display: inline; -} - -.uk-checkbox, .uk-radio{ - width: 16px !important; -} - -.uk-accordion table, .uk-card table { - border-collapse: inherit; -} - -.table-background-yellow { - background-color: #fff6ed; -} - -.table-background-yellow .uk-button { - border-color: darkorange; -} - -.table-background-red { - background-color: #ffe3e3; -} - -.table-background-red .uk-button{ - border-color: #a41515; -} - -.table-background-green { - background-color: #e5ffe3; -} - -.table-background-green .uk-button{ - border-color: #006b1b; -} - -.tira-button-selected, .tira-button-selected:hover { - border-color: #006b1b; - color: #006b1b; -} - -@keyframes flash-green-keyframes { - from {background-color: #006b1b;} - to {background-color: white;} -} - -@keyframes flash-red-keyframes { - from {background-color: darkred;} - to {background-color: white;} -} - -.flash-red { - animation-name: flash-red-keyframes; - animation-duration: 3s; -} - -.flash-green { - animation-name: flash-green-keyframes; - animation-duration: 3s; -} - -@media (max-width: 800px) { - .index-main-cover { - height: 200px - } -} - -@media (max-width: 400px) { - .index-main-cover { - height: 175px - } -} - -@media (max-width: 300px) { - .index-main-cover { - height: 150px - } -} - -@media (min-width: 960px) { - .index-main-cover { - height: 300px; - min-height: 200px; - } -} -/* strange disraptor hover fixes? */ -.disraptor-content .sortable:hover { - background-color: revert; -} -.disraptor-content .webis-data-table .sortable { - cursor: revert; -} - -.submit-button { - width: 100%; - border-radius: 5px; - margin-top: 5px; -} - -.hide-element { - display: none; -} diff --git a/application/src/tira/static/tira/img/background1.jpg b/application/src/tira/static/tira/img/background1.jpg deleted file mode 100644 index f40dfc3e0..000000000 Binary files a/application/src/tira/static/tira/img/background1.jpg and /dev/null differ diff --git a/application/src/tira/static/tira/img/background2.jpg b/application/src/tira/static/tira/img/background2.jpg deleted file mode 100644 index c90e49dd4..000000000 Binary files a/application/src/tira/static/tira/img/background2.jpg and /dev/null differ diff --git a/application/src/tira/static/tira/img/google-icon.png b/application/src/tira/static/tira/img/google-icon.png deleted file mode 100644 index 7c4c9f85f..000000000 Binary files a/application/src/tira/static/tira/img/google-icon.png and /dev/null differ diff --git a/application/src/tira/static/tira/img/ia-icon.png b/application/src/tira/static/tira/img/ia-icon.png deleted file mode 100644 index 4a5b2c67b..000000000 Binary files a/application/src/tira/static/tira/img/ia-icon.png and /dev/null differ diff --git a/application/src/tira/static/tira/img/image-licence.txt b/application/src/tira/static/tira/img/image-licence.txt deleted file mode 100644 index b27b52844..000000000 --- a/application/src/tira/static/tira/img/image-licence.txt +++ /dev/null @@ -1,2 +0,0 @@ -v1 - https://www.istockphoto.com/de/foto/blauen-und-wei%C3%9Fen-kirchen-von-oia-santorin-griechenland-gm164015369-23359009 -v2 - https://www.shutterstock.com/image-photo/sunset-oia-santorini-greece-1005762703 \ No newline at end of file diff --git a/application/src/tira/static/tira/img/logo-tira-32x32.png b/application/src/tira/static/tira/img/logo-tira-32x32.png deleted file mode 100644 index e69de29bb..000000000 diff --git a/application/src/tira/static/tira/img/logo-tira-40x40-transparent.png b/application/src/tira/static/tira/img/logo-tira-40x40-transparent.png deleted file mode 100644 index ae5bc7167..000000000 Binary files a/application/src/tira/static/tira/img/logo-tira-40x40-transparent.png and /dev/null differ diff --git a/application/src/tira/static/tira/img/logo-tira-40x40.png b/application/src/tira/static/tira/img/logo-tira-40x40.png deleted file mode 100644 index 3ead968de..000000000 Binary files a/application/src/tira/static/tira/img/logo-tira-40x40.png and /dev/null differ diff --git a/application/src/tira/static/tira/img/zenodo-icon.png b/application/src/tira/static/tira/img/zenodo-icon.png deleted file mode 100644 index 5578cb0a2..000000000 Binary files a/application/src/tira/static/tira/img/zenodo-icon.png and /dev/null differ diff --git a/application/src/tira/static/tira/js/review.js b/application/src/tira/static/tira/js/review.js deleted file mode 100644 index af2f29b67..000000000 --- a/application/src/tira/static/tira/js/review.js +++ /dev/null @@ -1,107 +0,0 @@ -let vm_id = null; -let dataset_id = null; -let run_id = null; - -// change view when blind state changes -function setBlindButton(blinded){ - if ( blinded === false ) { - $('#blind-button').show() - $('#blind-text').show() - $('#unblind-button').hide() - $('#unblind-text').hide() - } else { - $('#blind-button').hide() - $('#blind-text').hide() - $('#unblind-button').show() - $('#unblind-text').show() - } -} - -// change view when published state changes -function setPublishButton(published){ - if ( published === true ) { - $('#publish-button').hide(); - $('#publish-text').hide(); - $('#unpublish-button').show(); - $('#unpublish-text').show(); - } else { - $('#publish-button').show(); - $('#publish-text').show(); - $('#unpublish-button').hide(); - $('#unpublish-text').hide(); - } -} - -// when publish state changes: notify server and update view if successful -function publish(bool) { - $.ajax({ - type:"GET", - url: "/publish/" + vm_id + "/" + dataset_id + "/" + run_id + "/" + bool, - data: {}, - success: function( data ) - { - if(data.status === "0"){ - setPublishButton(data.published) - } - } - }) -} - -// when blind state changes: notify server and update view if successful -function blind(bool) { - $.ajax({ - type:"GET", - url: "/blind/" + vm_id + "/" + dataset_id + "/" + run_id + "/" + bool, - data:{}, - success: function( data ) - { - if(data.status === "0"){ - setBlindButton(data.blinded) - } - } - }) -} - -/* Init state and events for this page -* - initial state of blind, publish, and review -* - events for publishing and blinding -* - events to uncheck checkboxes -*/ -function addReviewEvents(p, b, vid, did, rid) { - vm_id = vid; - dataset_id =did; - run_id = rid; - p = p !== "False"; // Convert booleans to JS style - b = b !== "False"; - setPublishButton(p) - setBlindButton(b) - - $('#blind-button').click(function () { - blind(true) - }) - $('#unblind-button').click(function () { - blind(false) - }) - $('#publish-button').click(function () { - publish(true) - }) - $('#unpublish-button').click(function () { - publish(false) - }) - $('#no-error-checkbox').change(function () { - if(this.checked) { - $('#software-error-checkbox').prop('checked', false); - $('#output-error-checkbox').prop('checked', false); - } - }) - $('#software-error-checkbox').change(function () { - if(this.checked) { - $('#no-error-checkbox').prop('checked', false); - } - }) - $('#output-error-checkbox').change(function () { - if(this.checked) { - $('#no-error-checkbox').prop('checked', false); - } - }) -} \ No newline at end of file diff --git a/application/src/tira/templates/tira/background_jobs.html b/application/src/tira/templates/tira/background_jobs.html deleted file mode 100644 index b894ac7e5..000000000 --- a/application/src/tira/templates/tira/background_jobs.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends 'tira/base.html' %} -{% load render_bundle from webpack_loader %} -{% block title %}TIRA{% endblock %} -{% block navbar %}{% include "tira/navbar.html" with nav_active='tasks' %}{% endblock %} - -{% block content %} -{% csrf_token %} - -{% if include_navigation %} - - - -{% endif %} - - - - - -
- -
- -
-
-

TIRA — Background Job: {{job.title}}

- - If your job is finished (i.e., you see the output that you expect and there is an success exit code of 0), please go back to your task
/task/{{task}}. - Please refresh the page to see updates. - -

Metadata

-
    -
  • Last Contact to the Job: {{job.last_contact}}
  • -
  • Exit code: {{job.exit_code}}
  • -
- -

Stdout/Stderr of the job

-
-        {{job.stdout}}
-        
-
- -
- -{% endblock %} - - - diff --git a/application/src/tira/templates/tira/base.html b/application/src/tira/templates/tira/base.html deleted file mode 100644 index 5b6f0c536..000000000 --- a/application/src/tira/templates/tira/base.html +++ /dev/null @@ -1,44 +0,0 @@ - -{% load static %} - - - {% block title %}{% endblock %} - - - - - - - - - - - - - - - - - - -
-{% block navbar %}{% endblock %} -{% block content %}{% endblock %} -
-
- - - - - diff --git a/application/src/tira/templates/tira/navbar.html b/application/src/tira/templates/tira/navbar.html deleted file mode 100644 index 86ea0f9b4..000000000 --- a/application/src/tira/templates/tira/navbar.html +++ /dev/null @@ -1,62 +0,0 @@ -{% load static %} -{% if include_navigation %} -
-
- - - - -
-
- - -{% endif %} \ No newline at end of file diff --git a/application/src/tira/tests/tests.py b/application/src/tira/tests/tests.py deleted file mode 100644 index bd3ace575..000000000 --- a/application/src/tira/tests/tests.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.test import TestCase - - -class TestSetup(TestCase): - def setUp(self) -> None: - self.setup = True - - def test_setup_success(self): - """test if tests work""" - self.assertTrue(self.setup) diff --git a/application/src/tira/__init__.py b/application/src/tira_app/__init__.py similarity index 100% rename from application/src/tira/__init__.py rename to application/src/tira_app/__init__.py diff --git a/application/src/tira/admin.py b/application/src/tira_app/admin.py similarity index 89% rename from application/src/tira/admin.py rename to application/src/tira_app/admin.py index f2aadbf6e..8cf462a55 100644 --- a/application/src/tira/admin.py +++ b/application/src/tira_app/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -import tira.model as modeldb +from . import model as modeldb # Register your models here. diff --git a/application/src/tira/apps.py b/application/src/tira_app/apps.py similarity index 61% rename from application/src/tira/apps.py rename to application/src/tira_app/apps.py index 36a51708e..926187884 100644 --- a/application/src/tira/apps.py +++ b/application/src/tira_app/apps.py @@ -2,4 +2,5 @@ class TiraConfig(AppConfig): - name = "tira" + name = "tira_app" + label = "tira" diff --git a/application/src/tira/authentication.py b/application/src/tira_app/authentication.py similarity index 99% rename from application/src/tira/authentication.py rename to application/src/tira_app/authentication.py index 7118380ca..90fef41bb 100644 --- a/application/src/tira/authentication.py +++ b/application/src/tira_app/authentication.py @@ -8,7 +8,7 @@ from django.http import HttpRequest, HttpResponseNotAllowed from slugify import slugify -import tira.tira_model as model +from . import tira_model as model logger = logging.getLogger(__name__) @@ -474,7 +474,7 @@ def user_is_organizer_for_endpoint( ) -auth = Authentication(authentication_source=settings.DEPLOYMENT) +auth = Authentication(authentication_source="disraptor") """ diff --git a/application/src/tira/checks.py b/application/src/tira_app/checks.py similarity index 99% rename from application/src/tira/checks.py rename to application/src/tira_app/checks.py index c659bc02a..854acee0d 100644 --- a/application/src/tira/checks.py +++ b/application/src/tira_app/checks.py @@ -6,8 +6,7 @@ from django.shortcuts import redirect from django.urls import resolve -import tira.tira_model as model - +from . import tira_model as model from .authentication import auth logger = logging.getLogger("tira") diff --git a/application/src/tira/data/FileDatabase.py b/application/src/tira_app/data/FileDatabase.py similarity index 99% rename from application/src/tira/data/FileDatabase.py rename to application/src/tira_app/data/FileDatabase.py index b1bed39d6..9a687075e 100644 --- a/application/src/tira/data/FileDatabase.py +++ b/application/src/tira_app/data/FileDatabase.py @@ -10,8 +10,8 @@ from django.conf import settings from google.protobuf.text_format import Parse -from tira.proto import TiraClientWebMessages_pb2 as modelpb -from tira.util import TiraModelWriteError, auto_reviewer, extract_year_from_dataset_id +from ..proto import TiraClientWebMessages_pb2 as modelpb +from ..util import TiraModelWriteError, auto_reviewer, extract_year_from_dataset_id logger = logging.getLogger("tira") diff --git a/application/src/tira/data/HybridDatabase.py b/application/src/tira_app/data/HybridDatabase.py similarity index 99% rename from application/src/tira/data/HybridDatabase.py rename to application/src/tira_app/data/HybridDatabase.py index 404d5a643..0ee0d8dff 100644 --- a/application/src/tira/data/HybridDatabase.py +++ b/application/src/tira_app/data/HybridDatabase.py @@ -12,10 +12,9 @@ from django.db import IntegrityError from google.protobuf.text_format import Parse -import tira.data.data as dbops -import tira.model as modeldb -from tira.proto import TiraClientWebMessages_pb2 as modelpb -from tira.util import ( +from .. import model as modeldb +from ..proto import TiraClientWebMessages_pb2 as modelpb +from ..util import ( TiraModelIntegrityError, TiraModelWriteError, auto_reviewer, @@ -24,6 +23,7 @@ link_to_discourse_team, now, ) +from . import data as dbops logger = logging.getLogger("tira_db") diff --git a/application/src/tira/data/data.py b/application/src/tira_app/data/data.py similarity index 98% rename from application/src/tira/data/data.py rename to application/src/tira_app/data/data.py index b63dadf4a..f57b3fcc9 100644 --- a/application/src/tira/data/data.py +++ b/application/src/tira_app/data/data.py @@ -3,14 +3,13 @@ """ import logging -from pathlib import Path from google.protobuf.text_format import Parse from tqdm import tqdm -import tira.model as modeldb -from tira.proto import TiraClientWebMessages_pb2 as modelpb -from tira.util import auto_reviewer, extract_year_from_dataset_id +from .. import model as modeldb +from ..proto import TiraClientWebMessages_pb2 as modelpb +from ..util import auto_reviewer, extract_year_from_dataset_id logger = logging.getLogger("tira") diff --git a/application/src/tira/endpoints/admin_api.py b/application/src/tira_app/endpoints/admin_api.py similarity index 98% rename from application/src/tira/endpoints/admin_api.py rename to application/src/tira_app/endpoints/admin_api.py index de1ba68f8..4f5820399 100644 --- a/application/src/tira/endpoints/admin_api.py +++ b/application/src/tira_app/endpoints/admin_api.py @@ -11,11 +11,11 @@ from django.core.serializers.json import DjangoJSONEncoder from django.http import JsonResponse -import tira.tira_model as model -from tira.authentication import auth -from tira.checks import check_conditional_permissions, check_permissions, check_resources_exist -from tira.git_runner import check_that_git_integration_is_valid -from tira.ir_datasets_loader import run_irds_command +from .. import tira_model as model +from ..authentication import auth +from ..checks import check_conditional_permissions, check_permissions, check_resources_exist +from ..git_runner import check_that_git_integration_is_valid +from ..ir_datasets_loader import run_irds_command logger = logging.getLogger("tira") logger.info("ajax_routes: Logger active") @@ -481,6 +481,7 @@ def admin_import_ir_dataset(request, task_id): git_repository_id, ) + # TODO: what is the up-to-date href for background_jobs? try: process_id = run_irds_command( ds["task"], diff --git a/application/src/tira/endpoints/aha b/application/src/tira_app/endpoints/aha similarity index 100% rename from application/src/tira/endpoints/aha rename to application/src/tira_app/endpoints/aha diff --git a/application/src/tira/endpoints/data_api.py b/application/src/tira_app/endpoints/data_api.py similarity index 98% rename from application/src/tira/endpoints/data_api.py rename to application/src/tira_app/endpoints/data_api.py index a33463b63..6ba47371c 100644 --- a/application/src/tira/endpoints/data_api.py +++ b/application/src/tira_app/endpoints/data_api.py @@ -14,12 +14,12 @@ from django.http import HttpResponse, JsonResponse from slugify import slugify -import tira.tira_model as model -from tira.authentication import auth -from tira.checks import check_permissions, check_resources_exist -from tira.tira_data import get_run_file_list, get_run_runtime, get_stderr, get_stdout, get_tira_log -from tira.util import link_to_discourse_team -from tira.views import _add_user_vms_to_context, add_context +from .. import tira_model as model +from ..authentication import auth +from ..checks import check_permissions, check_resources_exist +from ..tira_data import get_run_file_list, get_run_runtime, get_stderr, get_stdout, get_tira_log +from ..util import link_to_discourse_team +from ..views import _add_user_vms_to_context, add_context include_navigation = False diff --git a/application/src/tira/endpoints/diffir_api.py b/application/src/tira_app/endpoints/diffir_api.py similarity index 97% rename from application/src/tira/endpoints/diffir_api.py rename to application/src/tira_app/endpoints/diffir_api.py index 61d287a19..164af8a45 100644 --- a/application/src/tira/endpoints/diffir_api.py +++ b/application/src/tira_app/endpoints/diffir_api.py @@ -6,9 +6,9 @@ from django.conf import settings from django.http import HttpResponse, JsonResponse -import tira.tira_model as model -from tira.checks import check_permissions -from tira.views import add_context +from .. import tira_model as model +from ..checks import check_permissions +from ..views import add_context logger = logging.getLogger("tira") diff --git a/application/src/tira/endpoints/misc.py b/application/src/tira_app/endpoints/misc.py similarity index 90% rename from application/src/tira/endpoints/misc.py rename to application/src/tira_app/endpoints/misc.py index 2b5435c6a..dbd32dc64 100644 --- a/application/src/tira/endpoints/misc.py +++ b/application/src/tira_app/endpoints/misc.py @@ -7,11 +7,8 @@ from rest_framework.decorators import api_view from rest_framework.request import Request from rest_framework.response import Response +from tira import __version__ as tira_version -# TODO: this does not work so I hardcoded for now -# from tira import __version__ as tira_version - -tira_version = "0.0.136" rest_api_version = "v1.0.0-draft" diff --git a/application/src/tira/endpoints/organizer_api.py b/application/src/tira_app/endpoints/organizer_api.py similarity index 93% rename from application/src/tira/endpoints/organizer_api.py rename to application/src/tira_app/endpoints/organizer_api.py index 955eabd95..7b3bc07d5 100644 --- a/application/src/tira/endpoints/organizer_api.py +++ b/application/src/tira_app/endpoints/organizer_api.py @@ -2,8 +2,8 @@ from django.http import JsonResponse -import tira.tira_model as model -from tira.checks import check_conditional_permissions, check_permissions, check_resources_exist +from .. import tira_model as model +from ..checks import check_conditional_permissions, check_permissions, check_resources_exist include_navigation = False diff --git a/application/src/tira/endpoints/serp_api.py b/application/src/tira_app/endpoints/serp_api.py similarity index 92% rename from application/src/tira/endpoints/serp_api.py rename to application/src/tira_app/endpoints/serp_api.py index 836db5be2..06360a717 100644 --- a/application/src/tira/endpoints/serp_api.py +++ b/application/src/tira_app/endpoints/serp_api.py @@ -4,9 +4,9 @@ from django.conf import settings from django.http import HttpResponse, JsonResponse -from tira.checks import check_permissions -from tira.endpoints.diffir_api import doc_file_for_run -from tira.views import add_context +from ..checks import check_permissions +from ..endpoints.diffir_api import doc_file_for_run +from ..views import add_context logger = logging.getLogger("tira") diff --git a/application/src/tira/endpoints/stdout_beautifier.py b/application/src/tira_app/endpoints/stdout_beautifier.py similarity index 100% rename from application/src/tira/endpoints/stdout_beautifier.py rename to application/src/tira_app/endpoints/stdout_beautifier.py diff --git a/application/src/tira/endpoints/v1/__init__.py b/application/src/tira_app/endpoints/v1/__init__.py similarity index 100% rename from application/src/tira/endpoints/v1/__init__.py rename to application/src/tira_app/endpoints/v1/__init__.py diff --git a/application/src/tira/endpoints/v1/_datasets.py b/application/src/tira_app/endpoints/v1/_datasets.py similarity index 100% rename from application/src/tira/endpoints/v1/_datasets.py rename to application/src/tira_app/endpoints/v1/_datasets.py diff --git a/application/src/tira/endpoints/v1/_evaluations.py b/application/src/tira_app/endpoints/v1/_evaluations.py similarity index 100% rename from application/src/tira/endpoints/v1/_evaluations.py rename to application/src/tira_app/endpoints/v1/_evaluations.py diff --git a/application/src/tira/endpoints/v1/_organizers.py b/application/src/tira_app/endpoints/v1/_organizers.py similarity index 100% rename from application/src/tira/endpoints/v1/_organizers.py rename to application/src/tira_app/endpoints/v1/_organizers.py diff --git a/application/src/tira/endpoints/v1/_runs.py b/application/src/tira_app/endpoints/v1/_runs.py similarity index 100% rename from application/src/tira/endpoints/v1/_runs.py rename to application/src/tira_app/endpoints/v1/_runs.py diff --git a/application/src/tira/endpoints/v1/_tasks.py b/application/src/tira_app/endpoints/v1/_tasks.py similarity index 100% rename from application/src/tira/endpoints/v1/_tasks.py rename to application/src/tira_app/endpoints/v1/_tasks.py diff --git a/application/src/tira/endpoints/v1/_user.py b/application/src/tira_app/endpoints/v1/_user.py similarity index 100% rename from application/src/tira/endpoints/v1/_user.py rename to application/src/tira_app/endpoints/v1/_user.py diff --git a/application/src/tira/endpoints/vm_api.py b/application/src/tira_app/endpoints/vm_api.py similarity index 98% rename from application/src/tira/endpoints/vm_api.py rename to application/src/tira_app/endpoints/vm_api.py index f2a766dba..d614436e5 100644 --- a/application/src/tira/endpoints/vm_api.py +++ b/application/src/tira_app/endpoints/vm_api.py @@ -12,13 +12,13 @@ from grpc import RpcError, StatusCode from markdown import markdown -import tira.tira_model as model -from tira.authentication import auth -from tira.checks import check_conditional_permissions, check_permissions, check_resources_exist -from tira.grpc_client import GrpcClient -from tira.model import EvaluationLog, TransitionLog -from tira.util import get_tira_id, link_to_discourse_team, reroute_host -from tira.views import add_context +from .. import tira_model as model +from ..authentication import auth +from ..checks import check_conditional_permissions, check_permissions, check_resources_exist +from ..grpc_client import GrpcClient +from ..model import EvaluationLog, TransitionLog +from ..util import get_tira_id, link_to_discourse_team, reroute_host +from ..views import add_context include_navigation = False @@ -161,7 +161,7 @@ def docker_software_details(request, context, vm_id, docker_software_id): @check_permissions def huggingface_model_mounts(request, vm_id, hf_model): - from tira.huggingface_hub_integration import huggingface_model_mounts, snapshot_download_hf_model + from ..huggingface_hub_integration import huggingface_model_mounts, snapshot_download_hf_model context = {"hf_model_available": False, "hf_model_for_vm": vm_id} @@ -569,7 +569,7 @@ def docker_software_add(request, task_id, vm_id): if data.get("mount_hf_model"): try: - from tira.huggingface_hub_integration import huggingface_model_mounts + from ..huggingface_hub_integration import huggingface_model_mounts mounts = huggingface_model_mounts(data.get("mount_hf_model")) model.add_docker_software_mounts(new_docker_software, mounts) @@ -925,7 +925,7 @@ def run_details(request, task_id, vm_id, run_id): ) elif "upload_id" in run and run["upload_id"]: - import tira.model as modeldb + from .. import model as modeldb run_upload = modeldb.Upload.objects.filter(vm__vm_id=vm_id, id=run["upload_id"]).get() vm_id_from_run = run_upload.vm.vm_id @@ -1027,6 +1027,7 @@ def run_execute_docker_software( visit_job_message = "Failed to start job." + # TODO: what is a new URL for that? if background_process: visit_job_message = ( f"Please visit https://tira.io/background_jobs/{task_id}/{background_process} " diff --git a/application/src/tira/git_runner.py b/application/src/tira_app/git_runner.py similarity index 90% rename from application/src/tira/git_runner.py rename to application/src/tira_app/git_runner.py index 39883afd3..df8207aee 100644 --- a/application/src/tira/git_runner.py +++ b/application/src/tira_app/git_runner.py @@ -6,7 +6,7 @@ def all_git_runners(): - from tira.tira_model import model + from .tira_model import model ret = [] for git_integration in model.all_git_integrations(return_dict=True): @@ -20,8 +20,8 @@ def all_git_runners(): def check_that_git_integration_is_valid(namespace_url, private_token): - import tira.model as modeldb - from tira.tira_model import model + from . import model as modeldb + from .tira_model import model git_integration = {"namespace_url": namespace_url, "private_token": private_token} @@ -48,7 +48,7 @@ def check_that_git_integration_is_valid(namespace_url, private_token): def get_git_runner(git_integration): - from tira.git_runner_integration import GithubRunner, GitLabRunner + from .git_runner_integration import GithubRunner, GitLabRunner if not git_integration or "namespace_url" not in git_integration: return None @@ -68,6 +68,6 @@ def get_git_runner(git_integration): def get_git_runner_for_software_integration(): - from tira.git_runner_integration import GithubRunner + from .git_runner_integration import GithubRunner return GithubRunner(settings.GITHUB_TOKEN) diff --git a/application/src/tira/git_runner_integration.py b/application/src/tira_app/git_runner_integration.py similarity index 99% rename from application/src/tira/git_runner_integration.py rename to application/src/tira_app/git_runner_integration.py index 356cc9724..213cdca21 100644 --- a/application/src/tira/git_runner_integration.py +++ b/application/src/tira_app/git_runner_integration.py @@ -21,8 +21,8 @@ from slugify import slugify from tqdm import tqdm -from tira.grpc_client import new_transaction -from tira.model import EvaluationLog, TransactionLog +from .grpc_client import new_transaction +from .model import EvaluationLog, TransactionLog logger = logging.getLogger("tira") @@ -493,7 +493,7 @@ def yield_all_running_pipelines(self, git_repository_id): raise ValueError("ToDo: Implement.") def archive_software(self, working_directory, software_definition, download_images, persist_images, upload_images): - from tira.util import docker_image_details, run_cmd + from .util import docker_image_details, run_cmd image = ( software_definition["TIRA_EVALUATION_IMAGE_TO_EXECUTE"] @@ -562,7 +562,7 @@ def archive_repository( ): from django.template.loader import render_to_string - from tira.tira_model import get_dataset, get_docker_software, get_docker_softwares_with_runs + from .tira_model import get_dataset, get_docker_software, get_docker_softwares_with_runs softwares = set() evaluations = set() @@ -1232,7 +1232,7 @@ def extract_job_configuration(self, gl_project, branch): software_from_db = {"display_name": "Evaluate Run", "image": "evaluator", "command": "evaluator"} else: try: - from tira.tira_model import model + from .tira_model import model software_from_db = model.get_docker_software(int(ret["TIRA_SOFTWARE_ID"].split("docker-software-")[-1])) except Exception as e: diff --git a/application/src/tira/grpc/grpc_server.py b/application/src/tira_app/grpc/grpc_server.py similarity index 98% rename from application/src/tira/grpc/grpc_server.py rename to application/src/tira_app/grpc/grpc_server.py index 1c7a305a6..7b97a2fc9 100644 --- a/application/src/tira/grpc/grpc_server.py +++ b/application/src/tira_app/grpc/grpc_server.py @@ -5,9 +5,9 @@ import grpc from django.conf import settings -import tira.tira_model as model -from tira.model import EvaluationLog, TransactionLog, TransitionLog -from tira.proto import tira_host_pb2, tira_host_pb2_grpc +from .. import tira_model as model +from ..model import EvaluationLog, TransactionLog, TransitionLog +from ..proto import tira_host_pb2, tira_host_pb2_grpc grpc_port = settings.APPLICATION_GRPC_PORT diff --git a/application/src/tira/grpc/test_grpc_host_client.py b/application/src/tira_app/grpc/test_grpc_host_client.py similarity index 98% rename from application/src/tira/grpc/test_grpc_host_client.py rename to application/src/tira_app/grpc/test_grpc_host_client.py index c9a5cf0e9..74e117ea2 100644 --- a/application/src/tira/grpc/test_grpc_host_client.py +++ b/application/src/tira_app/grpc/test_grpc_host_client.py @@ -1,6 +1,6 @@ import grpc -from tira.proto import tira_host_pb2, tira_host_pb2_grpc +from ..proto import tira_host_pb2, tira_host_pb2_grpc class TestGrpcHostClient: diff --git a/application/src/tira/grpc/test_grpc_host_server.py b/application/src/tira_app/grpc/test_grpc_host_server.py similarity index 99% rename from application/src/tira/grpc/test_grpc_host_server.py rename to application/src/tira_app/grpc/test_grpc_host_server.py index 8027bbe39..bd5a60766 100644 --- a/application/src/tira/grpc/test_grpc_host_server.py +++ b/application/src/tira_app/grpc/test_grpc_host_server.py @@ -9,8 +9,8 @@ import grpc -from tira.grpc.test_grpc_host_client import TestGrpcHostClient -from tira.proto import tira_host_pb2, tira_host_pb2_grpc +from tira_app.grpc.test_grpc_host_client import TestGrpcHostClient +from tira_app.proto import tira_host_pb2, tira_host_pb2_grpc VIRTUAL_MACHINES: dict[str, "DummyVirtualMachine"] = {} diff --git a/application/src/tira/grpc_client.py b/application/src/tira_app/grpc_client.py similarity index 99% rename from application/src/tira/grpc_client.py rename to application/src/tira_app/grpc_client.py index d4761314f..6a7449050 100644 --- a/application/src/tira/grpc_client.py +++ b/application/src/tira_app/grpc_client.py @@ -10,8 +10,7 @@ from django.conf import settings from google.protobuf.empty_pb2 import Empty -from tira.model import EvaluationLog, TransactionLog - +from .model import EvaluationLog, TransactionLog from .proto import tira_host_pb2, tira_host_pb2_grpc logger = logging.getLogger("tira") diff --git a/application/src/tira/huggingface_hub_integration.py b/application/src/tira_app/huggingface_hub_integration.py similarity index 99% rename from application/src/tira/huggingface_hub_integration.py rename to application/src/tira_app/huggingface_hub_integration.py index 4724d6eb7..4c92a1115 100644 --- a/application/src/tira/huggingface_hub_integration.py +++ b/application/src/tira_app/huggingface_hub_integration.py @@ -1,10 +1,9 @@ from typing import Iterable, Optional +import tira.io_utils as tira_cli_io_utils from huggingface_hub import HFCacheInfo, scan_cache_dir, snapshot_download from huggingface_hub.constants import HF_HOME -import tira.io_utils as tira_cli_io_utils - HF_CACHE: Optional[HFCacheInfo] = None diff --git a/application/src/tira/ir_datasets_loader.py b/application/src/tira_app/ir_datasets_loader.py similarity index 99% rename from application/src/tira/ir_datasets_loader.py rename to application/src/tira_app/ir_datasets_loader.py index 226f2fb48..067e2b479 100644 --- a/application/src/tira/ir_datasets_loader.py +++ b/application/src/tira_app/ir_datasets_loader.py @@ -12,8 +12,8 @@ def run_irds_command(task_id, dataset_id, image, command, output_dir, truth_command, truth_output_dir): - from tira.tira_model import model - from tira.util import run_cmd_as_documented_background_process + from .tira_model import model + from .util import run_cmd_as_documented_background_process irds_root = model.custom_irds_datasets_path / task_id / dataset_id command = command.replace("$outputDir", "/output-tira-tmp/") diff --git a/application/src/tira/management/commands/archive_runs_to_zenodo.py b/application/src/tira_app/management/commands/archive_runs_to_zenodo.py similarity index 99% rename from application/src/tira/management/commands/archive_runs_to_zenodo.py rename to application/src/tira_app/management/commands/archive_runs_to_zenodo.py index 910e30712..f02ef92f7 100644 --- a/application/src/tira/management/commands/archive_runs_to_zenodo.py +++ b/application/src/tira_app/management/commands/archive_runs_to_zenodo.py @@ -4,8 +4,8 @@ from django.core.management.base import BaseCommand from tqdm import tqdm -from tira.endpoints.data_api import model -from tira.views import zip_run, zip_runs +from ...endpoints.data_api import model +from ...views import zip_run, zip_runs def md5(filename): diff --git a/application/src/tira/management/commands/cache_daemon.py b/application/src/tira_app/management/commands/cache_daemon.py similarity index 97% rename from application/src/tira/management/commands/cache_daemon.py rename to application/src/tira_app/management/commands/cache_daemon.py index 21ff57155..c4f386bf2 100644 --- a/application/src/tira/management/commands/cache_daemon.py +++ b/application/src/tira_app/management/commands/cache_daemon.py @@ -6,11 +6,11 @@ from django.core.management import call_command from django.core.management.base import BaseCommand -import tira.tira_model as model +from ... import tira_model as model logger = logging.getLogger("cache_daemon") -from tira.git_runner import all_git_runners -from tira.tira_model import get_all_reranking_datasets, get_git_integration +from ...git_runner import all_git_runners +from ...tira_model import get_all_reranking_datasets, get_git_integration class Command(BaseCommand): diff --git a/application/src/tira/management/commands/dump_tira.py b/application/src/tira_app/management/commands/dump_tira.py similarity index 100% rename from application/src/tira/management/commands/dump_tira.py rename to application/src/tira_app/management/commands/dump_tira.py diff --git a/application/src/tira/management/commands/git_runner_cli.py b/application/src/tira_app/management/commands/git_runner_cli.py similarity index 98% rename from application/src/tira/management/commands/git_runner_cli.py rename to application/src/tira_app/management/commands/git_runner_cli.py index 551be04de..831afe867 100644 --- a/application/src/tira/management/commands/git_runner_cli.py +++ b/application/src/tira_app/management/commands/git_runner_cli.py @@ -6,13 +6,13 @@ from slugify import slugify from tqdm import tqdm -from tira.tira_model import ( +from ...tira_model import ( add_input_run_id_to_all_rerank_runs, create_re_rank_output_on_dataset, get_git_integration, load_refresh_timestamp_for_cache_key, ) -from tira.util import get_tira_id +from ...util import get_tira_id logger = logging.getLogger("tira") @@ -59,7 +59,7 @@ def run_command_stop_job_and_clean_up(self, options, git_runner): git_runner.stop_job_and_clean_up(options["stop_job_and_clean_up"], options["user_id"], options["run_id"]) def archive_repository_add_images_from_git_repo(self, options): - import tira.model as modeldb + from ... import model as modeldb with open(options["archive_repository_add_images_from_git_repo"], "r") as f: for line in tqdm(f): @@ -83,8 +83,8 @@ def archive_repository_add_images_from_git_repo(self, options): software.save() def archive_docker_software(self, approach, git_runner): - import tira.model as modeldb - from tira.util import docker_image_details + from ... import model as modeldb + from ...util import docker_image_details task_id, vm_id, name = approach.split("/") software = modeldb.DockerSoftware.objects.filter( diff --git a/application/src/tira/management/commands/grpc_mock_host.py b/application/src/tira_app/management/commands/grpc_mock_host.py similarity index 91% rename from application/src/tira/management/commands/grpc_mock_host.py rename to application/src/tira_app/management/commands/grpc_mock_host.py index 03f68216b..f25a61766 100644 --- a/application/src/tira/management/commands/grpc_mock_host.py +++ b/application/src/tira_app/management/commands/grpc_mock_host.py @@ -7,8 +7,8 @@ from django.conf import settings from django.core.management.base import BaseCommand -from tira.grpc.test_grpc_host_server import TiraHostService -from tira.proto import tira_host_pb2_grpc +from ...grpc.test_grpc_host_server import TiraHostService +from ...proto import tira_host_pb2_grpc grpc_host_port = settings.HOST_GRPC_PORT diff --git a/application/src/tira/management/commands/grpc_server.py b/application/src/tira_app/management/commands/grpc_server.py similarity index 91% rename from application/src/tira/management/commands/grpc_server.py rename to application/src/tira_app/management/commands/grpc_server.py index e7d7a524a..19f59ecdf 100644 --- a/application/src/tira/management/commands/grpc_server.py +++ b/application/src/tira_app/management/commands/grpc_server.py @@ -7,8 +7,8 @@ from django.conf import settings from django.core.management.base import BaseCommand -from tira.grpc.grpc_server import TiraApplicationService -from tira.proto import tira_host_pb2_grpc +from ...grpc.grpc_server import TiraApplicationService +from ...proto import tira_host_pb2_grpc grpc_port = settings.APPLICATION_GRPC_PORT listen_addr = f"[::]:{grpc_port}" diff --git a/application/src/tira/management/commands/index_model.py b/application/src/tira_app/management/commands/index_model.py similarity index 89% rename from application/src/tira/management/commands/index_model.py rename to application/src/tira_app/management/commands/index_model.py index 5df293c79..e4ddddd18 100644 --- a/application/src/tira/management/commands/index_model.py +++ b/application/src/tira_app/management/commands/index_model.py @@ -16,6 +16,6 @@ def handle(self, *args, **options): call_command("makemigrations") call_command("makemigrations", "tira") call_command("migrate") - from tira.data.HybridDatabase import HybridDatabase + from ...data.HybridDatabase import HybridDatabase HybridDatabase().create_model() diff --git a/application/src/tira/management/commands/ir_datasets_loader_cli.py b/application/src/tira_app/management/commands/ir_datasets_loader_cli.py similarity index 98% rename from application/src/tira/management/commands/ir_datasets_loader_cli.py rename to application/src/tira_app/management/commands/ir_datasets_loader_cli.py index 5287586d8..968904bab 100644 --- a/application/src/tira/management/commands/ir_datasets_loader_cli.py +++ b/application/src/tira_app/management/commands/ir_datasets_loader_cli.py @@ -4,7 +4,7 @@ from django.core.management.base import BaseCommand -from tira.ir_datasets_loader import IrDatasetsLoader +from ...ir_datasets_loader import IrDatasetsLoader logger = logging.getLogger("tira") diff --git a/application/src/tira/management/commands/irds_cli.sh b/application/src/tira_app/management/commands/irds_cli.sh similarity index 100% rename from application/src/tira/management/commands/irds_cli.sh rename to application/src/tira_app/management/commands/irds_cli.sh diff --git a/application/src/tira/management/commands/playground.py b/application/src/tira_app/management/commands/playground.py similarity index 93% rename from application/src/tira/management/commands/playground.py rename to application/src/tira_app/management/commands/playground.py index 10aa7aa51..9be832c3e 100644 --- a/application/src/tira/management/commands/playground.py +++ b/application/src/tira_app/management/commands/playground.py @@ -7,7 +7,7 @@ class Command(BaseCommand): """Runs some playground command.""" def handle(self, *args, **options): - from tira.git_runner import all_git_runners + from ...git_runner import all_git_runners g = all_git_runners() assert len(g) == 1 @@ -28,7 +28,7 @@ def handle(self, *args, **options): # context = {'user_id': 'mf2'} # print(add_registration(request, context, 'ir-lab-jena-leipzig-sose-2023', 'del-me-maik')) - # from tira.ir_datasets_loader import run_irds_command + # from ...ir_datasets_loader import run_irds_command # run_irds_command('tmp-test-maik', 'pssda', 'webis/tira-ir-datasets-starter:0.0.45-pangram', '/irds_cli.sh --skip_qrels true --ir_datasets_id pangrams --output_dataset_path $outputDir', '/tmp/sda-1/1/') # run_irds_command('tmp-test-maik', 'pssda', 'webis/tira-ir-datasets-starter:0.0.45-pangram', '/irds_cli.sh --skip_documents true --ir_datasets_id pangrams --output_dataset_truth_path $outputDir', '/tmp/sda-1/2/') diff --git a/application/src/tira/management/commands/run_develop.py b/application/src/tira_app/management/commands/run_develop.py similarity index 100% rename from application/src/tira/management/commands/run_develop.py rename to application/src/tira_app/management/commands/run_develop.py diff --git a/application/src/tira/management/commands/run_mockup.py b/application/src/tira_app/management/commands/run_mockup.py similarity index 91% rename from application/src/tira/management/commands/run_mockup.py rename to application/src/tira_app/management/commands/run_mockup.py index caa6a0de7..774bf499a 100644 --- a/application/src/tira/management/commands/run_mockup.py +++ b/application/src/tira_app/management/commands/run_mockup.py @@ -7,9 +7,9 @@ from django.core.management import call_command from django.core.management.base import BaseCommand -from tira.grpc.grpc_server import TiraApplicationService -from tira.grpc.test_grpc_host_server import TiraHostService -from tira.proto import tira_host_pb2_grpc +from ...grpc.grpc_server import TiraApplicationService +from ...grpc.test_grpc_host_server import TiraHostService +from ...proto import tira_host_pb2_grpc grpc_app_port = settings.APPLICATION_GRPC_PORT grpc_host_port = settings.HOST_GRPC_PORT diff --git a/application/src/tira/management/commands/run_to_evaluations.py b/application/src/tira_app/management/commands/run_to_evaluations.py similarity index 96% rename from application/src/tira/management/commands/run_to_evaluations.py rename to application/src/tira_app/management/commands/run_to_evaluations.py index 7cfe5ca78..fd64a0cca 100644 --- a/application/src/tira/management/commands/run_to_evaluations.py +++ b/application/src/tira_app/management/commands/run_to_evaluations.py @@ -2,7 +2,7 @@ from django.core.management.base import BaseCommand -import tira.tira_model as model +from ... import tira_model as model class Command(BaseCommand): diff --git a/application/src/tira/model.py b/application/src/tira_app/model.py similarity index 100% rename from application/src/tira/model.py rename to application/src/tira_app/model.py diff --git a/application/src/tira/permissions.py b/application/src/tira_app/permissions.py similarity index 100% rename from application/src/tira/permissions.py rename to application/src/tira_app/permissions.py diff --git a/application/src/tira/proto/TiraClientWebMessages_pb2.py b/application/src/tira_app/proto/TiraClientWebMessages_pb2.py similarity index 100% rename from application/src/tira/proto/TiraClientWebMessages_pb2.py rename to application/src/tira_app/proto/TiraClientWebMessages_pb2.py diff --git a/application/src/tira/proto/TiraClientWebMessages_pb2_grpc.py b/application/src/tira_app/proto/TiraClientWebMessages_pb2_grpc.py similarity index 100% rename from application/src/tira/proto/TiraClientWebMessages_pb2_grpc.py rename to application/src/tira_app/proto/TiraClientWebMessages_pb2_grpc.py diff --git a/application/src/tira/proto/TiraHostMessages_pb2.py b/application/src/tira_app/proto/TiraHostMessages_pb2.py similarity index 100% rename from application/src/tira/proto/TiraHostMessages_pb2.py rename to application/src/tira_app/proto/TiraHostMessages_pb2.py diff --git a/application/src/tira/proto/TiraHostMessages_pb2_grpc.py b/application/src/tira_app/proto/TiraHostMessages_pb2_grpc.py similarity index 100% rename from application/src/tira/proto/TiraHostMessages_pb2_grpc.py rename to application/src/tira_app/proto/TiraHostMessages_pb2_grpc.py diff --git a/application/src/tira/proto/__init__.py b/application/src/tira_app/proto/__init__.py similarity index 100% rename from application/src/tira/proto/__init__.py rename to application/src/tira_app/proto/__init__.py diff --git a/application/src/tira/proto/tira_host_pb2.py b/application/src/tira_app/proto/tira_host_pb2.py similarity index 100% rename from application/src/tira/proto/tira_host_pb2.py rename to application/src/tira_app/proto/tira_host_pb2.py diff --git a/application/src/tira/proto/tira_host_pb2_grpc.py b/application/src/tira_app/proto/tira_host_pb2_grpc.py similarity index 100% rename from application/src/tira/proto/tira_host_pb2_grpc.py rename to application/src/tira_app/proto/tira_host_pb2_grpc.py diff --git a/application/src/tira/proto/tira_messages_pb2.py b/application/src/tira_app/proto/tira_messages_pb2.py similarity index 100% rename from application/src/tira/proto/tira_messages_pb2.py rename to application/src/tira_app/proto/tira_messages_pb2.py diff --git a/application/src/tira/proto/tira_to_web_pb2.py b/application/src/tira_app/proto/tira_to_web_pb2.py similarity index 100% rename from application/src/tira/proto/tira_to_web_pb2.py rename to application/src/tira_app/proto/tira_to_web_pb2.py diff --git a/application/src/tira/proto/tira_to_web_pb2_grpc.py b/application/src/tira_app/proto/tira_to_web_pb2_grpc.py similarity index 100% rename from application/src/tira/proto/tira_to_web_pb2_grpc.py rename to application/src/tira_app/proto/tira_to_web_pb2_grpc.py diff --git a/application/src/tirex-components.yml b/application/src/tira_app/res/tirex-components.yml similarity index 100% rename from application/src/tirex-components.yml rename to application/src/tira_app/res/tirex-components.yml diff --git a/application/src/tira/templates/tira/git-repo-template/Dockerfile b/application/src/tira_app/templates/tira/git-repo-template/Dockerfile similarity index 100% rename from application/src/tira/templates/tira/git-repo-template/Dockerfile rename to application/src/tira_app/templates/tira/git-repo-template/Dockerfile diff --git a/application/src/tira/templates/tira/git-repo-template/README.md b/application/src/tira_app/templates/tira/git-repo-template/README.md similarity index 100% rename from application/src/tira/templates/tira/git-repo-template/README.md rename to application/src/tira_app/templates/tira/git-repo-template/README.md diff --git a/application/src/tira/templates/tira/git-repo-template/github-action.yml b/application/src/tira_app/templates/tira/git-repo-template/github-action.yml similarity index 100% rename from application/src/tira/templates/tira/git-repo-template/github-action.yml rename to application/src/tira_app/templates/tira/git-repo-template/github-action.yml diff --git a/application/src/tira/templates/tira/git-repo-template/script.py b/application/src/tira_app/templates/tira/git-repo-template/script.py similarity index 100% rename from application/src/tira/templates/tira/git-repo-template/script.py rename to application/src/tira_app/templates/tira/git-repo-template/script.py diff --git a/application/src/tira/templates/tira/git_task_repository_gitlab_ci.yml b/application/src/tira_app/templates/tira/git_task_repository_gitlab_ci.yml similarity index 100% rename from application/src/tira/templates/tira/git_task_repository_gitlab_ci.yml rename to application/src/tira_app/templates/tira/git_task_repository_gitlab_ci.yml diff --git a/application/src/tira/templates/tira/git_task_repository_readme.md b/application/src/tira_app/templates/tira/git_task_repository_readme.md similarity index 100% rename from application/src/tira/templates/tira/git_task_repository_readme.md rename to application/src/tira_app/templates/tira/git_task_repository_readme.md diff --git a/application/src/tira/templates/tira/git_user_repository_readme.md b/application/src/tira_app/templates/tira/git_user_repository_readme.md similarity index 100% rename from application/src/tira/templates/tira/git_user_repository_readme.md rename to application/src/tira_app/templates/tira/git_user_repository_readme.md diff --git a/application/src/tira/templates/tira/tira_git_cmd.py b/application/src/tira_app/templates/tira/tira_git_cmd.py similarity index 100% rename from application/src/tira/templates/tira/tira_git_cmd.py rename to application/src/tira_app/templates/tira/tira_git_cmd.py diff --git a/application/src/tira/templates/tira/tira_git_cmd.sh b/application/src/tira_app/templates/tira/tira_git_cmd.sh similarity index 100% rename from application/src/tira/templates/tira/tira_git_cmd.sh rename to application/src/tira_app/templates/tira/tira_git_cmd.sh diff --git a/application/src/tira/templates/tira/tira_git_makefile b/application/src/tira_app/templates/tira/tira_git_makefile similarity index 100% rename from application/src/tira/templates/tira/tira_git_makefile rename to application/src/tira_app/templates/tira/tira_git_makefile diff --git a/application/src/tira/templates/tira/tira_git_tutorial.ipynb b/application/src/tira_app/templates/tira/tira_git_tutorial.ipynb similarity index 100% rename from application/src/tira/templates/tira/tira_git_tutorial.ipynb rename to application/src/tira_app/templates/tira/tira_git_tutorial.ipynb diff --git a/application/src/tira/tira_data.py b/application/src/tira_app/tira_data.py similarity index 98% rename from application/src/tira/tira_data.py rename to application/src/tira_app/tira_data.py index eef5c2afc..e0bcf9b0d 100644 --- a/application/src/tira/tira_data.py +++ b/application/src/tira_app/tira_data.py @@ -3,7 +3,7 @@ from django.conf import settings -from tira.endpoints.stdout_beautifier import beautify_ansi_text +from .endpoints.stdout_beautifier import beautify_ansi_text logger = logging.getLogger("tira") diff --git a/application/src/tira/tira_model.py b/application/src/tira_app/tira_model.py similarity index 99% rename from application/src/tira/tira_model.py rename to application/src/tira_app/tira_model.py index 607f9aa32..bf96f9242 100644 --- a/application/src/tira/tira_model.py +++ b/application/src/tira_app/tira_model.py @@ -16,9 +16,9 @@ from django.db import connections, router from slugify import slugify -from tira.data.HybridDatabase import HybridDatabase -from tira.git_runner import get_git_runner, get_git_runner_for_software_integration -from tira.util import get_tira_id, register_run +from .data.HybridDatabase import HybridDatabase +from .git_runner import get_git_runner, get_git_runner_for_software_integration +from .util import get_tira_id, register_run logger = logging.getLogger("tira") @@ -662,7 +662,7 @@ def all_allowed_task_teams(task_id): def user_is_registered(task_id, request): - from tira.authentication import auth + from .authentication import auth allowed_task_teams = all_allowed_task_teams(task_id) user_vm_ids = [i.strip() for i in auth.get_vm_ids(request) if i.strip()] diff --git a/application/src/tira/urls.py b/application/src/tira_app/urls.py similarity index 99% rename from application/src/tira/urls.py rename to application/src/tira_app/urls.py index fb289d3a4..72cca7c10 100644 --- a/application/src/tira/urls.py +++ b/application/src/tira_app/urls.py @@ -8,7 +8,6 @@ from .endpoints.v1 import endpoints as v1_endpoints urlpatterns: list[Union[URLResolver, URLPattern]] = [ - path("background_jobs//", views.background_jobs, name="background_jobs"), path( "task//user//dataset//download/.zip", views.download_rundir, diff --git a/application/src/tira/util.py b/application/src/tira_app/util.py similarity index 88% rename from application/src/tira/util.py rename to application/src/tira_app/util.py index ab767c6aa..455956842 100644 --- a/application/src/tira/util.py +++ b/application/src/tira_app/util.py @@ -5,8 +5,6 @@ from django.conf import settings -from tira import tira_model - from .proto import TiraClientWebMessages_pb2 as modelpb logger = logging.getLogger("tira") @@ -115,6 +113,11 @@ def link_to_discourse_team(vm_id): def register_run(dataset_id, vm_id, run_id, software_id): + # import tira_model has to be done here since it has a side-effect with django and throws + # django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet. + # if it is imported before django is launched otherwise. + from . import tira_model + path_for_run = Path(settings.TIRA_ROOT) / "data" / "runs" / dataset_id / vm_id / run_id with open(path_for_run / "run.prototext", "w") as f: @@ -132,7 +135,7 @@ def __run_cmd_as_documented_background_process(cmds, process_id, descriptions, c from subprocess import STDOUT, Popen from time import sleep - import tira.model as modeldb + from . import model as modeldb with tempfile.NamedTemporaryFile() as file: file.write("".encode("utf8")) @@ -165,7 +168,7 @@ def run_cmd_as_documented_background_process(cmd, vm_id, task_id, title, descrip import json import threading - import tira.model as modeldb + from . import model as modeldb process_id = modeldb.BackendProcess.objects.create( vm_id=vm_id, task_id=task_id, cmd=json.dumps(cmd), title=title @@ -192,3 +195,12 @@ def docker_image_details(image): ret = ret[0] image_id = ret["Id"] if ":" not in ret["Id"] else ret["Id"].split(":")[1] return {"image_id": image_id, "size": ret["Size"], "virtual_size": ret["VirtualSize"]} + + +def str2bool(text: str) -> bool: + """ + Extracts the boolean meaning of the given text. A string of the form "yes", "y", "true", "t", and "1" is + considered to express the boolean value True. The string may be in upper case as well (e.g., TRUE or True) and may + be surrounded by whitespaces. Any value that is not considered true, will return false. + """ + return text.strip().lower() in ("yes", "y", "true", "t", "1") diff --git a/application/src/tira/views.py b/application/src/tira_app/views.py similarity index 96% rename from application/src/tira/views.py rename to application/src/tira_app/views.py index 2f3fcdf58..b200081a5 100644 --- a/application/src/tira/views.py +++ b/application/src/tira_app/views.py @@ -14,8 +14,7 @@ from django.template.loader import render_to_string from django.utils.safestring import mark_safe -import tira.tira_model as model - +from . import tira_model as model from .authentication import auth from .checks import check_conditional_permissions, check_permissions, check_resources_exist @@ -49,15 +48,6 @@ def func_wrapper(request, *args, **kwargs): return func_wrapper -@check_permissions -@add_context -def background_jobs(request, context, task_id, job_id): - context["task"] = task_id - context["job"] = model.get_job_details(task_id, None, job_id) - - return render(request, "tira/background_jobs.html", context) - - def _add_task_to_context(context, task_id, dataset_id): datasets = model.get_datasets_by_task(task_id) diff --git a/application/test/api_access_matrix.py b/application/test/api_access_matrix.py index 11258ecbd..9f85c0dee 100644 --- a/application/test/api_access_matrix.py +++ b/application/test/api_access_matrix.py @@ -472,28 +472,6 @@ ORGANIZER_WRONG_TASK: 405, }, ), - route_to_test( - url_pattern="background_jobs//", - params={"task_id": "does-not-exist", "job_id": -1}, - group_to_expected_status_code={ - ADMIN: 200, - GUEST: 405, - PARTICIPANT: 405, - ORGANIZER: 405, - ORGANIZER_WRONG_TASK: 405, - }, - ), - route_to_test( - url_pattern="background_jobs//", - params={"task_id": "task-of-organizer-1", "job_id": -1}, - group_to_expected_status_code={ - ADMIN: 200, - GUEST: 405, - PARTICIPANT: 405, - ORGANIZER: 200, - ORGANIZER_WRONG_TASK: 405, - }, - ), route_to_test( url_pattern="task//vm//add_software/vm", params={"task_id": "shared-task-1", "vm_id": "example_participant"}, diff --git a/application/test/auth_tests/test_is_admin_for_task.py b/application/test/auth_tests/test_is_admin_for_task.py index 16a2056bf..88b5a9d35 100644 --- a/application/test/auth_tests/test_is_admin_for_task.py +++ b/application/test/auth_tests/test_is_admin_for_task.py @@ -1,7 +1,7 @@ from django.test import TestCase from utils_for_testing import mock_request, set_up_tira_environment -from tira.authentication import auth +from tira_app.authentication import auth submit_url_task_1 = "submit/task-of-organizer-1" overview_url_task_1 = "task-overview/task-of-organizer-1" diff --git a/application/test/evaluation_api_integration_tests/test_evaluations_for_vm.py b/application/test/evaluation_api_integration_tests/test_evaluations_for_vm.py index 00339d85c..59763fe92 100644 --- a/application/test/evaluation_api_integration_tests/test_evaluations_for_vm.py +++ b/application/test/evaluation_api_integration_tests/test_evaluations_for_vm.py @@ -4,8 +4,8 @@ from django.test import TestCase from utils_for_testing import method_for_url_pattern, mock_request, now, set_up_tira_filesystem -import tira.model as modeldb -from tira.tira_model import model as tira_model +import tira_app.model as modeldb +from tira_app.tira_model import model as tira_model url = "api/evaluations-of-vm//" evaluations_function = method_for_url_pattern(url) diff --git a/application/test/git_runner_integration_tests/test_rendering_of_job_file.py b/application/test/git_runner_integration_tests/test_rendering_of_job_file.py index f1a9436c1..715d7ceec 100644 --- a/application/test/git_runner_integration_tests/test_rendering_of_job_file.py +++ b/application/test/git_runner_integration_tests/test_rendering_of_job_file.py @@ -2,7 +2,7 @@ from django.test import TestCase -from tira.git_runner_integration import GitRunner +from tira_app.git_runner_integration import GitRunner class TestRenderingOfJobFile(TestCase): diff --git a/application/test/hf_mount_model_tests/test_hf_mounts_are_parsed.py b/application/test/hf_mount_model_tests/test_hf_mounts_are_parsed.py index cf0640e8a..c4b4bc18b 100644 --- a/application/test/hf_mount_model_tests/test_hf_mounts_are_parsed.py +++ b/application/test/hf_mount_model_tests/test_hf_mounts_are_parsed.py @@ -2,7 +2,7 @@ from huggingface_hub import snapshot_download -from tira.huggingface_hub_integration import _hf_repos, huggingface_model_mounts +from tira_app.huggingface_hub_integration import _hf_repos, huggingface_model_mounts class TestHfMountsAreParsed(unittest.TestCase): diff --git a/application/test/multi_step_job_tests/test_multi_step_jobs_with_alternative_input.py b/application/test/multi_step_job_tests/test_multi_step_jobs_with_alternative_input.py index 6e1629cb3..2c4fd9030 100644 --- a/application/test/multi_step_job_tests/test_multi_step_jobs_with_alternative_input.py +++ b/application/test/multi_step_job_tests/test_multi_step_jobs_with_alternative_input.py @@ -3,8 +3,8 @@ from django.test import TestCase from utils_for_testing import set_up_tira_environment -import tira.model as modeldb -from tira.tira_model import latest_output_of_software_on_dataset +import tira_app.model as modeldb +from tira_app.tira_model import latest_output_of_software_on_dataset # Used for some tests now = datetime.now().strftime("%Y%m%d") diff --git a/application/test/multi_step_job_tests/test_multi_step_jobs_with_multiple_inputs.py b/application/test/multi_step_job_tests/test_multi_step_jobs_with_multiple_inputs.py index 7ff25764a..43dc655ed 100644 --- a/application/test/multi_step_job_tests/test_multi_step_jobs_with_multiple_inputs.py +++ b/application/test/multi_step_job_tests/test_multi_step_jobs_with_multiple_inputs.py @@ -1,7 +1,7 @@ from django.test import TestCase from utils_for_testing import set_up_tira_environment, software_non_public, software_public, software_with_inputs -from tira.tira_model import model +from tira_app.tira_model import model PARTICIPANT = "PARTICIPANT-FOR-TEST-1" TASK = "shared-task-1" diff --git a/application/test/organizer_api_integration_tests/test_creation_of_dataset_id.py b/application/test/organizer_api_integration_tests/test_creation_of_dataset_id.py index 9e240a9f0..e13b151da 100644 --- a/application/test/organizer_api_integration_tests/test_creation_of_dataset_id.py +++ b/application/test/organizer_api_integration_tests/test_creation_of_dataset_id.py @@ -3,7 +3,7 @@ from django.test import TestCase from utils_for_testing import set_up_tira_environment -from tira.tira_model import model +from tira_app.tira_model import model now = datetime.now().strftime("%Y%m%d") diff --git a/application/test/settings_test.py b/application/test/settings_test.py index 6f5394b63..64bfda392 100644 --- a/application/test/settings_test.py +++ b/application/test/settings_test.py @@ -10,49 +10,58 @@ https://docs.djangoproject.com/en/3.1/ref/settings/ """ +import importlib.resources as resources import logging import os from pathlib import Path import yaml +from pyaml_env import parse_config + +from tira_app.util import str2bool # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent custom_settings = {} -for cfg in (BASE_DIR / "config").glob("*.yml"): - custom_settings.update(yaml.load(open(cfg, "r").read(), Loader=yaml.FullLoader)) +cfgpath = os.environ.get("TIRA_CONFIG", str(BASE_DIR / "config" / "tira-application-config.yml")) +logging.info(f"Load settings from {cfgpath}.") +config = parse_config(cfgpath, default_value=None, loader=yaml.FullLoader) +custom_settings.update(config) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = str2bool(custom_settings["debug"]) + +if DEBUG: + logging.basicConfig(level=logging.DEBUG, force=True) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = custom_settings.get("django_secret", "not-so-secret") +# https://docs.djangoproject.com/en/5.1/ref/settings/#std-setting-SECRET_KEY +SECRET_KEY = custom_settings["django_secret"] -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = custom_settings.get("debug", True) -ALLOWED_HOSTS = custom_settings.get("allowed_hosts", []) +ALLOWED_HOSTS = custom_settings["allowed_hosts"] -TIRA_ROOT = Path(custom_settings.get("tira_root", BASE_DIR / "test" / "tira-root")) +TIRA_ROOT = Path(custom_settings["tira_root"]) if not TIRA_ROOT.is_dir(): logging.warning(f"{TIRA_ROOT} does not exists and will be created now.") (TIRA_ROOT / "state").mkdir(parents=True, exist_ok=True) -DEPLOYMENT = "disraptor" -DISRAPTOR_SECRET_FILE = Path(custom_settings.get("disraptor_secret_file", "/etc/discourse/client-api-key")) HOST_GRPC_PORT = custom_settings.get("host_grpc_port", "50051") APPLICATION_GRPC_PORT = custom_settings.get("application_grpc_port", "50052") GRPC_HOST = custom_settings.get("grpc_host", "local") # can be local or remote - +TIRA_DB_NAME = custom_settings["database"]["name"] TIRA_DB = { - "ENGINE": "django.db.backends.sqlite3", - "NAME": "test-database/sqlite3", - "USER": "tira", - "PASSWORD": "replace-with-db-password", - "HOST": "tira-mariadb", - "PORT": 3306, + "ENGINE": custom_settings["database"]["engine"], + "NAME": TIRA_DB_NAME, + "USER": custom_settings["database"]["user"], + "PASSWORD": custom_settings["database"]["password"], + "HOST": custom_settings["database"]["host"], + "PORT": int(custom_settings["database"]["port"]), "TEST": { "NAME": "test_tira", "ENGINE": "django.db.backends.sqlite3", @@ -61,7 +70,7 @@ # Application definition INSTALLED_APPS = [ - "tira.apps.TiraConfig", + "tira_app.apps.TiraConfig", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", @@ -69,7 +78,6 @@ "django_filters", "rest_framework", "rest_framework_json_api", - "webpack_loader", ] MIDDLEWARE = [ @@ -83,8 +91,9 @@ ] REST_FRAMEWORK = { - "DEFAULT_AUTHENTICATION_CLASSES": ("tira.authentication.TrustedHeaderAuthentication",), + "DEFAULT_AUTHENTICATION_CLASSES": ("tira_app.authentication.TrustedHeaderAuthentication",), "DEFAULT_FILTER_BACKENDS": ("rest_framework_json_api.django_filters.DjangoFilterBackend",), + "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",), } ROOT_URLCONF = "django_admin.urls" @@ -239,6 +248,20 @@ def logger_config(log_dir: Path): } +# Git Integration +GIT_CI_AVAILABLE_RESOURCES = { + "small-resources": { + "cores": 1, + "ram": 10, + "gpu": 0, + "data": "no", + "description": "Small (1 CPU Cores, 10GB of RAM)", + "key": "small-resources", + }, +} + +DEFAULT_GIT_INTEGRATION_URL = "https://git.webis.de/code-research/tira" + IR_MEASURES_IMAGE = custom_settings.get("IR_MEASURES_IMAGE", "webis/tira-ir-measures-evaluator:0.0.1") IR_MEASURES_COMMAND = custom_settings.get( "IR_MEASURES_COMMAND", @@ -246,6 +269,8 @@ def logger_config(log_dir: Path): ' ${inputDataset}/qrels.txt --output ${outputDir} --measures "P@10" "nDCG@10" "MRR"', ) +GITHUB_TOKEN = custom_settings["github_token"] + # Caching CACHES = { "default": { @@ -256,6 +281,10 @@ def logger_config(log_dir: Path): } } +TIREX_COMPONENTS = yaml.load( + (resources.files("tira_app.res") / "tirex-components.yml").read_bytes(), Loader=yaml.FullLoader +) + # Logging ld = Path(custom_settings.get("logging_dir", TIRA_ROOT / "log" / "tira-application")) try: @@ -273,24 +302,6 @@ def logger_config(log_dir: Path): raise PermissionError(f"Can not write to {ld} in production mode.") -# Password validation -# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ @@ -304,33 +315,15 @@ def logger_config(log_dir: Path): USE_TZ = True -WEBPACK_LOADER = { - "DEFAULT": { - "CACHE": DEBUG, - "BUNDLE_DIR_NAME": "/bundles/", - "STATS_FILE": BASE_DIR / "src" / "tira" / "frontend" / "webpack-stats.json", - } -} - -TIREX_COMPONENTS = yaml.load(open(BASE_DIR / "src" / "tirex-components.yml").read(), Loader=yaml.FullLoader) - -GIT_CI_AVAILABLE_RESOURCES = { - "small-resources": { - "cores": 1, - "ram": 10, - "gpu": 0, - "data": "no", - "description": "Small (1 CPU Cores, 10GB of RAM)", - "key": "small-resources", - } -} +DISCOURSE_API_URL = custom_settings["discourse_api_url"] +DISRAPTOR_API_KEY = custom_settings["discourse_api_key"] +PUBLIC_TRAINING_DATA = set(["jena-topics-20231026-test", "leipzig-topics-20231025-test"]) CODE_SUBMISSION_REFERENCE_REPOSITORIES = { "ir-lab-jena-leipzig-wise-2023": "mam10eks/tira-software-submission-template", "webpage-classification": "OpenWebSearch/irixys23-tira-submission-template", } -CODE_SUBMISSION_REPOSITORY_NAMESPACE = "tira-io" -DISRAPTOR_API_KEY = "" -DISCOURSE_API_URL = "" -PUBLIC_TRAINING_DATA = set(["jena-topics-20231026-test", "leipzig-topics-20231025-test"]) + REFERENCE_DATASETS: dict[str, str] = {} + +CODE_SUBMISSION_REPOSITORY_NAMESPACE = "tira-io" diff --git a/application/test/utils_for_testing.py b/application/test/utils_for_testing.py index 6ed4eb4f8..c3beaff82 100644 --- a/application/test/utils_for_testing.py +++ b/application/test/utils_for_testing.py @@ -16,9 +16,9 @@ from django.urls import URLPattern, URLResolver from rest_framework.test import APIRequestFactory -import tira.model as modeldb -from tira.authentication import TrustedHeaderAuthentication -from tira.tira_model import model as tira_model +import tira_app.model as modeldb +from tira_app.authentication import TrustedHeaderAuthentication +from tira_app.tira_model import model as tira_model auth_backend = TrustedHeaderAuthentication() # There must be a way to get this from rest_framework right? diff --git a/documentation/development/backend/index.rst b/documentation/development/backend/index.rst index 946d1a9c2..deb7b1aea 100644 --- a/documentation/development/backend/index.rst +++ b/documentation/development/backend/index.rst @@ -21,4 +21,37 @@ Linting FAQ --- -Yay, no questions yet. \ No newline at end of file +Yay, no questions yet. + + + + +.. This was copied over from the deployment documentation and should be worked into the development documentation instead + Development + ~~~~~~~~~~~ + Frequently used development commands are: + + - Start the application without any grpc server + + .. code:: bash + + application/src~$ python3 manage.py runserver 8080 + + - Start only the application's grpc server + + .. code:: bash + + application/src~$ python3 manage.py grpc_server + + - Start the application and the application's grpc server. This is used in make run-develop and the container + + .. code:: bash + + application/src~$ python3 manage.py run_develop + + - Start the application, the application's grpc server, and a mock host grpc server that will reply to the application + with fake commands. This is the simplest way to develop the application. + + .. code:: bash + + application/src~$ python3 manage.py run_mockup diff --git a/documentation/organizers/deployment/application.rst b/documentation/organizers/deployment/application.rst index 56f09c16e..4580403e4 100644 --- a/documentation/organizers/deployment/application.rst +++ b/documentation/organizers/deployment/application.rst @@ -1,190 +1,71 @@ -Deploying the Application Module -================================ +Deploying the Backend +===================== -Development Setup ------------------ -The following steps will setup a self-contained, local tira application and a mockup tira host. See `Development`_ for -more detailed options. +.. important:: TIRA makes greate use of the internet forum tool `Discourse `_. Before you + continue, please set up a Discourse instance and install the reverse proxy plugin + `Disraptor `_. -.. code:: bash +The TIRA backend is entirely contained within the official docker image, +`ghcr.io/tira-io/tira-backend:latest `_. To see, what a +deployment using this container can look like, please have a look at our +:bdg-ref-secondary:`demo deployment `. - # Install Python3, pip and virtualenv - sudo apt-get update && \ - sudo apt-get install python3 python3-pip python3-venv libmysqlclient-dev - # Setup the local environment - make setup # This creates the virtual environment and prepares Django's database - # Setup the local environment - make run-develop # This updates the config and runs the server within the venv. - -Docker ------- -You can run tira in a docker container for a simple deployment. - -You need to run two docker containers for a tira-application: - -- :code:`registry.webis.de/code-lib/public-images/tira-application` and -- :code:`registry.webis.de/code-lib/public-images/tira-application-grpc`. - -.. code:: bash - - ~$ docker run -d --rm --name=tira-application \ - -p 8080:80 \ - -v="":/mnt/ceph/tira \ - registry.webis.de/code-lib/public-images/tira-application:latest - - ~$ docker run -d --rm --name=tira-application-grpc \ - -p 50052:50052 \ - -v="":/mnt/ceph/tira \ - registry.webis.de/code-lib/public-images/tira-application-grpc:latest - -Use TIRA with Discourse via Disraptor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. note:: This step is, in theory, optional but, if left out, user credentials will be transmitted and stored in - plaintext and can be read by anyone using the public REST-API. - -If you set up Discourse with `Disraptor `_, this will be useful information on how to -make TIRA work with it. - -(1) Since TIRA has a legacy and a Disraptor :code:`deployment` mode first change that to :code:`disraptor` in the - development config file :code:`application/config/tira-application-config.dev.yml`. -(2) When you set up Disraptor you set a :code:`Disraptor App Secret Key` that allows Disraptor to communicate with your - web application. Since TIRA has to evaluate that this secret is correct we have to supply it to it. TIRA expects - that secret in an environment variable called :code:`DISRAPTOR_APP_SECRET_KEY`, so before starting your development - TIRA environment with :code:`make run-develop` or :code:`make run-git-develop` always remember to - :code:`export DISRAPTOR_APP_SECRET_KEY=`. -(3) Lastly, of course, Disraptor has to be supplied with the routes for TIRA at :code:`Settings > Plugins > Disraptor`. - Since routes may change in the future and depending on what you want to test you maybe do no need the full set of - routes arranged it is recommended to take a look at :code:`application/src/tira/urls.py`. Here is an example of - what can be used to have access to most of the **current** TIRA: - - ========================== =============================================== ======== - From To Method - ========================== =============================================== ======== - `/public/tira/*wildcard` `http://127.0.0.1:8080/public/tira/*wildcard` GET - `/task/*wildcard` `http://127.0.0.1:8080/task/*wildcard` GET - `/task/*wildcard` `http://127.0.0.1:8080/task/*wildcard` POST - `/api/*wildcard` `http://127.0.0.1:8080/api/*wildcard` GET - `/tira-admin` `http://127.0.0.1:8080/tira-admin` GET - `/tira-admin/*wildcard` `http://127.0.0.1:8080/tira-admin/*wildcard` GET - `/tira-admin/*wildcard` `http://127.0.0.1:8080/tira-admin/*wildcard` POST - `/static/*wildcard` `http://127.0.0.1:8080/static/*wildcard` GET - `/grpc/*wildcard` `http://127.0.0.1:8080/grpc/*wildcard` GET - `/grpc/*wildcard` `http://127.0.0.1:8080/grpc/*wildcard` POST - `/tasks` `http://127.0.0.1:8080/` GET - `/tira/static/*wildcard` `http://127.0.0.1:8080/tira/static/*wildcard` GET - ========================== =============================================== ======== - - .. note:: - Let's say route A gets added here first and then route B. Rails will evaluate them from latest to earliest. So - when checking for a destination Rails will first look if route B matches before it checks route A and so on. - This can lead to states where you might see unexpected behavior if your routes (namely these with wildcards) - have interseting "To"-pools. - .. note:: - Sometimes Rails does not instantly take in new routes so when adding new routes you might want to restart the - Rails server. - -Build and Deploy +Configuring TIRA ---------------- -Run the tests -~~~~~~~~~~~~~ -.. code:: bash - - # run all tests in application/src/tira/tests - application/src~$ python3 manage.py test test tira/tests/ - # run an individual test module - application/src~$ python3 manage.py test test tira/tests/tests.py - -Deploy on Kubernetes -~~~~~~~~~~~~~~~~~~~~ -.. todo:: This step is deprecated and the documentation must be updated - -Add the discourse secret in the namespace via: - -.. code:: bash - - ??? TODO? - -Re-build the docker images -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: bash - - # Build the protobuf libraries from source. - make build - # This creates the virtual environment and prepares Django's database - make setup - # Build the docker image (deploy mode with nginx) - make docker-build-tira-application - # Run the docker container with the make command (deploy mode) - make docker-run-tira-application - # (optional) Publish a new version - make docker-publish-tira-application - -These make targets from the deployment configuration: :code:`tira/application/config/settings-deploy.yml`. - -Development -~~~~~~~~~~~ -The settings used for the development setup are: :code:`tira/application/config/settings-dev.yml`. - -Frequently used development commands are: - -- Start the application without any grpc server - - .. code:: bash - - application/src~$ python3 manage.py runserver 8080 - -- Start only the application's grpc server - - .. code:: bash - - application/src~$ python3 manage.py grpc_server - -- Start the application and the application's grpc server. This is used in make run-develop and the container - - .. code:: bash - - application/src~$ python3 manage.py run_develop - -- Start the application, the application's grpc server, and a mock host grpc server that will reply to the application - with fake commands. This is the simplest way to develop the application. - - .. code:: bash - - application/src~$ python3 manage.py run_mockup - -Troubleshooting ---------------- -If there are problems with the precompiled protobuf parser, you can recompile them from the :code:`tira/protocol` -repository and copy them to :code:`tira/application/src/tira/proto`. - -Setup on MacOS (Monterey/M1) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. attention:: - This part of the documentation is experimental and may not work for everyone. -.. note:: - We will assume that `brew `_ is installed. - -(1) Install required software - - .. code:: bash - - brew install python@3.10 pipenv pyvenv mariadb uwsgi -(2) Inside :code:`tira/application/config/tira-application-config.dev.yml` change :code:`tira_root` to the model you - want to use. -(3) From within :code:`tira/application` execute the makefile at least once. This copies the config and runs - :code:`manage.py index_model` once. - - .. code:: bash - - make setup - .. note:: - If above command did not work, you may try to build the venv and install the requirements manually by executing - the following commands within :code:`tira/application` - - .. code:: bash - - python3.10 -m venv venv - source venv/bin/activat - pip install -r requirements.txt +TIRA can be configured using two ways (non-exclusive): + +(1) Environment variables +(2) A configuration file + +To kill two birds with one stone (only figuratively speaking), we refer you to the fully documented default +configuration file (below). Any value of the form ``!ENV ${:}`` indicates that the value is read from the +environment variable ```` and, if that environment variable does not exist, the default value, ```` is +assigned. This means, that, to set TIRA into debug mode, for example, you have two options: + +(1) The line ``debug: !ENV ${TIRA_DEBUG:false}`` tells us that, per default, the debug mode is disabled but we can + enable it by setting the environment variable ``TIRA_DEBUG`` to ``true``. +(2) Copy the default configuration, replace ``debug: !ENV ${TIRA_DEBUG:false}`` with ``debug: true`` and map the new + configuration file into your container to ``/tira/config/tira-application-config.yml`` (this location can be + changed using the ``TIRA_CONFIG`` environment variable). + +.. literalinclude:: ../../../application/config/tira-application-config.yml + :language: yaml + :caption: TIRA's default configuration + +.. attention:: Some of these configuration parameters are **secrets** and should stay *secret*. Do not use their + default values for production and use `Docker secrets `_ + to set them. + + +Endpoints +--------- +Lastly, of course, Disraptor has to be supplied with the routes for TIRA at :code:`Settings > Plugins > Disraptor`. +Since routes may change in the future and depending on what you want to test you maybe do no need the full set of +routes arranged it is recommended to take a look at :code:`application/src/tira/urls.py`. Here is an example of +what can be used to have access to most of the **current** TIRA: + +========================== =============================================== ======== +From To Method +========================== =============================================== ======== +`/public/tira/*wildcard` `http://127.0.0.1:8080/public/tira/*wildcard` GET +`/task/*wildcard` `http://127.0.0.1:8080/task/*wildcard` GET +`/task/*wildcard` `http://127.0.0.1:8080/task/*wildcard` POST +`/api/*wildcard` `http://127.0.0.1:8080/api/*wildcard` GET +`/tira-admin` `http://127.0.0.1:8080/tira-admin` GET +`/tira-admin/*wildcard` `http://127.0.0.1:8080/tira-admin/*wildcard` GET +`/tira-admin/*wildcard` `http://127.0.0.1:8080/tira-admin/*wildcard` POST +`/static/*wildcard` `http://127.0.0.1:8080/static/*wildcard` GET +`/grpc/*wildcard` `http://127.0.0.1:8080/grpc/*wildcard` GET +`/grpc/*wildcard` `http://127.0.0.1:8080/grpc/*wildcard` POST +`/tasks` `http://127.0.0.1:8080/` GET +`/tira/static/*wildcard` `http://127.0.0.1:8080/tira/static/*wildcard` GET +`/health` `http://127.0.0.1:8080/health` GET +`/info` `http://127.0.0.1:8080/info` GET +`/v1/*wildcard` `http://127.0.0.1:8080/v1/*wildcard` GET +`/v1/*wildcard` `http://127.0.0.1:8080/v1/*wildcard` POST +`/v1/*wildcard` `http://127.0.0.1:8080/v1/*wildcard` DELETE +`/v1/*wildcard` `http://127.0.0.1:8080/v1/*wildcard` UPDATE +========================== =============================================== ======== + +.. important:: Routes that were added later take precedence over those added before when multiple rules match. +.. hint:: You may need to restart the Rails server to apply your changes. diff --git a/frontend/.gitignore b/frontend/.gitignore index b7e37f23c..a2bb187ba 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,3 +1,5 @@ +static/ + # Created by https://www.toptal.com/developers/gitignore/api/node,visualstudiocode,yarn,macos,linux,windows # Edit at https://www.toptal.com/developers/gitignore?templates=node,visualstudiocode,yarn,macos,linux,windows diff --git a/frontend/Dockerfile.prod b/frontend/Dockerfile.prod index 4f2e28615..1340aef20 100644 --- a/frontend/Dockerfile.prod +++ b/frontend/Dockerfile.prod @@ -36,8 +36,8 @@ EOF # src/tira.conf.js) with the respective environment variable's value. COPY --chmod=0755 < - + TIRA Reproducible Experiments
- + + + + - + \ No newline at end of file diff --git a/frontend/src/TaskOverview.vue b/frontend/src/TaskOverview.vue index 7c21f15d2..4738c9906 100644 --- a/frontend/src/TaskOverview.vue +++ b/frontend/src/TaskOverview.vue @@ -1,119 +1,126 @@ diff --git a/frontend/src/__tests__/url-extraction-test.ts b/frontend/src/__tests__/url-extraction-test.ts index 73d42f924..bb52b0dbb 100644 --- a/frontend/src/__tests__/url-extraction-test.ts +++ b/frontend/src/__tests__/url-extraction-test.ts @@ -1,8 +1,6 @@ import { extractTaskFromCurrentUrl, extractDatasetFromCurrentUrl, - extractSubView, - extractSubSubView, extractCurrentStepFromCurrentUrl, extractSubmissionTypeFromCurrentUrl, extractUserFromCurrentUrl, @@ -12,20 +10,20 @@ import { } from '../utils' Object.defineProperty((window as Window), 'location', { - value: { - href: '' - }, - writable: true // possibility to override - }); + value: { + href: '' + }, + writable: true // possibility to override +}); test('Task from current Url should be Null.', () => { - (window as Window).location.href = "http://dummy.com"; - expect(extractTaskFromCurrentUrl()).toBeNull(); + (window as Window).location.href = "http://dummy.com"; + expect(extractTaskFromCurrentUrl()).toBeNull(); }); test('Task from Url without Subpath Should be correct.', () => { - (window as Window).location.href = 'task-overview/abc' - expect(extractTaskFromCurrentUrl()).toStrictEqual('abc'); + (window as Window).location.href = 'task-overview/abc' + expect(extractTaskFromCurrentUrl()).toStrictEqual('abc'); }); test('Task from Url without Subpath Should be correct with question mark.', () => { @@ -39,8 +37,8 @@ test('Task from Url without Subpath Should be correct with # symbol.', () => { }); test('Task from Url with Subpath Should be correct.', () => { - (window as Window).location.href = 'task-overview/1234/' - expect(extractTaskFromCurrentUrl()).toStrictEqual('1234'); + (window as Window).location.href = 'task-overview/1234/' + expect(extractTaskFromCurrentUrl()).toStrictEqual('1234'); }); test('Dataset from Url without dataset should be the empty string.', () => { @@ -81,7 +79,7 @@ test('Dataset from Url with Subpath Should be correct.', () => { test('Dataset is extracted with precedence from the default_choice if available.', () => { (window as Window).location.href = 'task-overview/abc/ds' - let options = [{'dataset_id': 'ds'}, {'dataset_id': 'something-is-selected'}, {'dataset_id': 'ds2'}] + let options = [{ 'dataset_id': 'ds' }, { 'dataset_id': 'something-is-selected' }, { 'dataset_id': 'ds2' }] let selectedDataset = 'something-is-selected' expect(extractDatasetFromCurrentUrl(options, selectedDataset)).toStrictEqual('something-is-selected'); @@ -90,7 +88,7 @@ test('Dataset is extracted with precedence from the default_choice if available. test('First Dataset is extracted if the default_choice is not available.', () => { (window as Window).location.href = 'task-overview/abc' - let options = [{'dataset_id': 'ds'}, {'dataset_id': 'something-is-selected'}, {'dataset_id': 'ds2'}] + let options = [{ 'dataset_id': 'ds' }, { 'dataset_id': 'something-is-selected' }, { 'dataset_id': 'ds2' }] let selectedDataset = 'does-not-exist' expect(extractDatasetFromCurrentUrl(options, selectedDataset)).toStrictEqual('ds'); @@ -100,7 +98,7 @@ test('First Dataset is extracted if the default_choice is not available.', () => test('Dataset from URL is extracted if default_choice is wrong.', () => { (window as Window).location.href = 'task-overview/abc/ds2' - let options = [{'dataset_id': 'ds'}, {'dataset_id': 'something-is-selected'}, {'dataset_id': 'ds2'}] + let options = [{ 'dataset_id': 'ds' }, { 'dataset_id': 'something-is-selected' }, { 'dataset_id': 'ds2' }] let selectedDataset = 'does-not-exist' expect(extractDatasetFromCurrentUrl(options, selectedDataset)).toStrictEqual('ds2'); @@ -109,7 +107,7 @@ test('Dataset from URL is extracted if default_choice is wrong.', () => { test('Dataset from URL is extracted if no default_choice is available.', () => { (window as Window).location.href = 'task-overview/abc/ds2' - let options = [{'dataset_id': 'ds'}, {'dataset_id': 'something-is-selected'}, {'dataset_id': 'ds2'}] + let options = [{ 'dataset_id': 'ds' }, { 'dataset_id': 'something-is-selected' }, { 'dataset_id': 'ds2' }] let selectedDataset = '' expect(extractDatasetFromCurrentUrl(options, selectedDataset)).toStrictEqual('ds2'); @@ -119,7 +117,7 @@ test('Dataset from URL is extracted if no default_choice is available.', () => { test('First dataset is used if dataset from URL does not exist.', () => { (window as Window).location.href = 'task-overview/abc/ds2' - let options = [{'dataset_id': 'ds'}, {'dataset_id': 'something-is-selected'}, {'dataset_id': 'ds22'}] + let options = [{ 'dataset_id': 'ds' }, { 'dataset_id': 'something-is-selected' }, { 'dataset_id': 'ds22' }] let selectedDataset = '' expect(extractDatasetFromCurrentUrl(options, selectedDataset)).toStrictEqual('ds'); @@ -195,48 +193,12 @@ test('Expect current step from subpath to be null if not exists', () => { test('First dataset is used if dataset from URL does not exist and default_choise is wrong.', () => { (window as Window).location.href = 'task-overview/abc/ds2' - let options = [{'dataset_id': 'ds'}, {'dataset_id': 'something-is-selected'}, {'dataset_id': 'ds3'}] + let options = [{ 'dataset_id': 'ds' }, { 'dataset_id': 'something-is-selected' }, { 'dataset_id': 'ds3' }] let selectedDataset = 'does-not-exist' expect(extractDatasetFromCurrentUrl(options, selectedDataset)).toStrictEqual('ds'); }); -test('No sub-view and sub-sub-view exist 1.', () => { - (window as Window).location.href = 'task-overview/1234/' - expect(extractSubView()).toBeNull; - expect(extractSubSubView()).toBeNull; -}); - -test('No sub-view and sub-sub-view exist 2.', () => { - (window as Window).location.href = 'task-overview/1234/23' - expect(extractSubView()).toBeNull; - expect(extractSubSubView()).toBeNull; -}); - -test('No sub-view and sub-sub-view exist 2.', () => { - (window as Window).location.href = 'dummy/1234/23/hello/world/how' - expect(extractSubView()).toBeNull; - expect(extractSubSubView()).toBeNull; -}); - -test('Sub-view exists but no sub-sub-view 1.', () => { - (window as Window).location.href = 'task-overview/1234/23/sub-view-1' - expect(extractSubView()).toStrictEqual('sub-view-1'); - expect(extractSubSubView()).toBeNull; -}); - -test('Sub-view exists but no sub-sub-view 2.', () => { - (window as Window).location.href = 'task-overview/1234/23/1234' - expect(extractSubView()).toStrictEqual('1234'); - expect(extractSubSubView()).toBeNull; -}); - -test('Sub-view exists and sub-sub-view 1.', () => { - (window as Window).location.href = 'task-overview/1234/23/1234/sub-sub-view' - expect(extractSubView()).toStrictEqual('1234'); - expect(extractSubSubView()).toStrictEqual('sub-sub-view'); -}); - test('No component_type, no focus_type and no search_query exists', () => { (window as Window).location.href = 'dummy/1234/23/hello/world/how' expect(extractFocusTypesFromCurrentUrl()).toStrictEqual([]); @@ -321,7 +283,7 @@ test('Component_type and focus and search query exist 2', () => { test('Multiple component_type and focus and search query exist ', () => { (window as Window).location.href = 'components/TIREx,Code,Tutorial/Precision,Recall/Dense%20Retrieval/' - expect(extractComponentTypesFromCurrentUrl()).toStrictEqual(['TIREx','Code','Tutorial']); - expect(extractFocusTypesFromCurrentUrl()).toStrictEqual(['Precision','Recall']); + expect(extractComponentTypesFromCurrentUrl()).toStrictEqual(['TIREx', 'Code', 'Tutorial']); + expect(extractFocusTypesFromCurrentUrl()).toStrictEqual(['Precision', 'Recall']); expect(extractSearchQueryFromCurrentUrl()).toStrictEqual('dense retrieval'); }); diff --git a/frontend/src/__tests__/user-metadata-extraction-test.ts b/frontend/src/__tests__/user-metadata-extraction-test.ts index 58bf31719..8534d2f7e 100644 --- a/frontend/src/__tests__/user-metadata-extraction-test.ts +++ b/frontend/src/__tests__/user-metadata-extraction-test.ts @@ -1,40 +1,10 @@ -import { extractRole, extractCsrf } from '../utils' +import { extractCsrf } from '../utils' function doc(html: string) { return new DOMParser().parseFromString(html, 'text/html') } -test('Guest is the default role if a non-existing role is specified.', () => { - let d = doc('') - - expect(extractRole(d)).toBe('guest') -}); - -test('Guest is the default role if the json can not be parsed.', () => { - let d = doc('') - - expect(extractRole(d)).toBe('guest') -}); - -test('Guest is the default role if a valid json is in a different tag.', () => { - let d = doc('') - - expect(extractRole(d)).toBe('guest') -}); - -test('Extract admin if admin is specified.', () => { - let d = doc('') - - expect(extractRole(d)).toBe('admin') -}); - -test('Extract participant if participant is specified.', () => { - let d = doc('') - - expect(extractRole(d)).toBe('participant') -}); - test('Csrf Token can be extracted.', () => { let d = doc('
') diff --git a/frontend/src/components/EditTask.vue b/frontend/src/components/EditTask.vue index 8cae92145..3bc2d0856 100644 --- a/frontend/src/components/EditTask.vue +++ b/frontend/src/components/EditTask.vue @@ -1,121 +1,170 @@ - + diff --git a/frontend/src/components/RunActions.vue b/frontend/src/components/RunActions.vue index 9591e6e3e..420a33d14 100644 --- a/frontend/src/components/RunActions.vue +++ b/frontend/src/components/RunActions.vue @@ -1,106 +1,141 @@ diff --git a/frontend/src/components/RunList.vue b/frontend/src/components/RunList.vue index 234df27a0..aa0a49e9e 100644 --- a/frontend/src/components/RunList.vue +++ b/frontend/src/components/RunList.vue @@ -1,50 +1,54 @@