Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • dariah-de/textgridrep/repdav
1 result
Show changes
Commits on Source (9)
......@@ -7,16 +7,18 @@ workflow:
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
stages:
- test
- release
- build
- deploy
variables:
harbor_registry: "harbor.gwdg.de"
harbor_repo: "sub-fe"
project_name: "repdav"
lint dockerfile:
stage: test
......@@ -40,7 +42,7 @@ lint dockerfile:
release:
stage: release
image: docker.io/node:16.14
image: docker.io/node:18.12
before_script:
- npm ci --unsafe-perm
script:
......@@ -66,8 +68,49 @@ build container image:
--build-arg build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
--build-arg vcs_ref=${CI_COMMIT_SHORT_SHA}
--build-arg version=${version}
--destination $CI_REGISTRY_IMAGE/repdav:$version
--destination $harbor_registry/$harbor_repo/repdav:$version
--destination $CI_REGISTRY_IMAGE/$project_name:$version
--destination $harbor_registry/$harbor_repo/$project_name:$version
rules:
# prevent job creation on release commits to $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
when: never
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
generate app sbom:
stage: deploy
image: docker.io/node:18.12
before_script:
- npm ci --ignore-scripts
- npm run build
script:
- npx cdxgen
--type nodejs
--required-only
--server-url https://deps.sub.uni-goettingen.de
--api-key ${DEPS_UPLOAD_TOKEN}
--project-name ${project_name}
--project-version ${CI_COMMIT_TAG}
rules:
- if: $CI_COMMIT_TAG
generate container sbom:
stage: deploy
image: docker.io/alpine:3.16
before_script:
- apk add curl
- curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
script:
- syft --output cyclonedx-json --file bom.json
$CI_REGISTRY_IMAGE/${project_name}:${CI_COMMIT_TAG}
- 'curl -X POST "https://deps.sub.uni-goettingen.de/api/v1/bom"
--header "accept: application/json"
--header "X-Api-Key: ${DEPS_UPLOAD_TOKEN}"
--header "Content-Type: multipart/form-data"
--form "autoCreate=true"
--form "projectName=${project_name}-container"
--form "projectVersion=${CI_COMMIT_TAG}"
--form "bom=@bom.json"'
rules:
- if: $CI_COMMIT_TAG
# [1.2.0](https://gitlab.gwdg.de/dariah-de/textgridrep/repdav/compare/1.1.3...1.2.0) (2023-01-09)
### Features
* **textgrid_dav_provider:** initialize textgrid config with "tg_host" from wsgidav environ ([fab21bc](https://gitlab.gwdg.de/dariah-de/textgridrep/repdav/commit/fab21bcf60737f8d710f3e8419195ba10d20139f))
## [1.1.3](https://gitlab.gwdg.de/dariah-de/textgridrep/repdav/compare/1.1.2...1.1.3) (2022-11-29)
......
......@@ -11,14 +11,11 @@ services:
build:
context: .
ports:
- ${port:-8080}:${port:-8080}
- ${REPDAV_PORT:-8080}:${REPDAV_PORT:-8080}
environment:
host: ${host:-0.0.0.0}
port: ${port:-8080}
sentry_dsn: ${sentry_dsn}
tg_auth_wsdl: "https://textgridlab.org/1.0/tgauth/wsdl/tgextra.wsdl"
tg_auth_address: "https://textgridlab.org/1.0/tgauth/tgextra.php"
tg_nav_address: "https://textgridlab.org/1.0/tgsearch/navigation/"
tg_host: "https://textgridlab.org/"
REPDAV_HOST: ${REPDAV_HOST:-0.0.0.0}
REPDAV_PORT: ${REPDAV_PORT:-8080}
SENTRY_DSN: ${SENTRY_DSN}
TEXTGRID_HOST: ${TEXTGRID_HOST}
volumes:
- $PWD/src:/app
This diff is collapsed.
......@@ -2,10 +2,11 @@
"name": "repdav",
"private": true,
"devDependencies": {
"@semantic-release/changelog": "^6.0.1",
"@appthreat/cdxgen": "^6.0.0",
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/git": "^10.0.1",
"@semantic-release/gitlab": "^7.0.4",
"semantic-release": "^19.0.2"
"@semantic-release/gitlab": "^9.5.1",
"semantic-release": "^19.0.5"
},
"release": {
"branches": [
......@@ -38,7 +39,8 @@
{
"assets": [
"CHANGELOG.md"
]
],
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
}
]
]
......
......@@ -4,8 +4,6 @@
"""Configure and start the WSGI DAV Server."""
import logging
import os
import sentry_sdk
from cheroot import wsgi
from wsgidav.wsgidav_app import WsgiDAVApp
......@@ -14,13 +12,11 @@ from repdav.config import AppConfig
app_config = AppConfig()
if app_config.dsn:
sentry_sdk.init(
app_config.dsn,
traces_sample_rate=1.0
)
sentry_sdk.init(app_config.dsn, traces_sample_rate=1.0)
logging.basicConfig(level=logging.DEBUG,
format='%(name)s %(levelname)s %(asctime)s %(message)s')
logging.basicConfig(
level=logging.DEBUG, format="%(name)s %(levelname)s %(asctime)s %(message)s"
)
_logger = logging.getLogger(__name__)
_logger.propagate = True
......@@ -31,12 +27,13 @@ tmp_logger.setLevel(logging.DEBUG)
# Configuration of the WsgiDAVApp.
# https://wsgidav.readthedocs.io/en/latest/user_guide_configure.html
# TODO: move to config.py
config = {
"host": os.getenv("host") or "localhost",
"port": int(os.getenv("port") or "8080"),
"host": app_config.host,
"port": app_config.port,
"provider_mapping": {
"/": {"class": "repdav.textgrid_named_dav_provider.TextgridNamedResourceProvider"},
"/": {
"class": "repdav.textgrid_named_dav_provider.TextgridNamedResourceProvider"
},
},
"verbose": 4,
"http_authenticator": {
......@@ -47,7 +44,8 @@ config = {
"default_to_digest": False,
# Name of a header field that will be accepted as authorized user
"trusted_auth_header": None,
}
},
"tg_host": app_config.tg_host,
}
app = WsgiDAVApp(config)
......
......@@ -3,63 +3,51 @@
# SPDX-License-Identifier: CC0-1.0
import os
from typing import Optional
from urllib.parse import urlparse
from .errors import EnvNotSetError
# TODO: remove "tg_auth_wsdl", "tg_auth_address", "tg_nav_address"
def check_url(url):
"""Check if `url` can be parsed."""
if url:
result = urlparse(url)
if result.scheme and result.netloc:
return url
raise ValueError(f"{url} is not a valid URL.")
def lookup_env_name(internal_name: str) -> str:
mapping = {
"_auth_wsdl": "tg_auth_wsdl",
"_auth_address": "tg_auth_address",
"_dsn": "sentry_dsn",
"_host": "tg_host",
"_nav_address": "tg_nav_address",
}
return mapping[internal_name]
def check_port(port):
"""Check if port is set correctly to a non-privileged value."""
if 1000 <= port <= 65535:
return port
raise ValueError(f"{port} is not a valid Port.")
# TODO check for trailing "/", add if missing!
# TODO check URLs for validity
class AppConfig:
# TODO: configure the app according to the set environment (i.e. prod or dev)
def __init__(self) -> None:
self._dsn = os.getenv(lookup_env_name("_dsn"))
@property
def dsn(self) -> str:
return self._dsn
"""Settings that can be be configured from the environment."""
class TextgridConfig:
def __init__(self) -> None:
self._auth_wsdl = os.getenv(lookup_env_name("_auth_wsdl"))
self._auth_address = os.getenv(lookup_env_name("_auth_address"))
self._nav_address = os.getenv(lookup_env_name("_nav_address"))
self._host = os.getenv(lookup_env_name("_host"))
self._dsn = check_url(os.getenv("SENTRY_DSN"))
self._host = os.getenv("REPDAV_HOST") or "localhost"
self._port = check_port(int(os.getenv("REPDAV_PORT") or 8080))
self._tg_host = check_url(os.getenv("TEXTGRID_HOST"))
@property
def auth_wsdl(self) -> str:
if self._auth_wsdl:
return self._auth_wsdl
raise EnvNotSetError(lookup_env_name("_auth_wsdl"))
def dsn(self) -> Optional[str]:
"""Sentry DSN."""
return self._dsn
@property
def auth_address(self) -> str:
if self._auth_address:
return self._auth_address
raise EnvNotSetError(lookup_env_name("_auth_address"))
def host(self) -> str:
"""Service hostname."""
return self._host
@property
def nav_address(self) -> str:
if self._nav_address:
return self._nav_address
raise EnvNotSetError(lookup_env_name("_nav_address"))
def port(self) -> int:
"""Service port."""
return self._port
@property
def host(self) -> str:
if self._host:
return self._host
raise EnvNotSetError(lookup_env_name("_host"))
def tg_host(self) -> Optional[str]:
"""Textgrid host URL."""
return self._tg_host
......@@ -21,6 +21,16 @@ from repdav.stream_tools import FileLikeQueue
_logger = logging.getLogger(__name__)
def tg_config(environ):
"""Initialize Textgrid configuration either with or without host setting. This
works around an [issue with tgclients](https://gitlab.gwdg.de/dariah-de/textgridrep/textgrid-python-clients/-/issues/59).
"""
tg_host = environ["wsgidav.config"]["tg_host"]
if tg_host:
return TextgridConfig(tg_host)
return TextgridConfig()
class TextgridRoot(DAVCollection):
"""Top level collection that incorporates Textgrid projects.
......@@ -30,8 +40,9 @@ class TextgridRoot(DAVCollection):
def __init__(self, path, environ):
DAVCollection.__init__(self, path, environ)
self._sid = environ["wsgidav.auth.user_name"]
config = TextgridConfig()
config = tg_config(environ)
self._auth = TextgridAuth(config)
self.projects = ()
def get_display_info(self):
return {"type": "Textgrid root collection"}
......@@ -83,7 +94,7 @@ class TextgridProject(DAVCollection):
_logger.debug("Called TextgridProject.__init__(self, %s, environ).", path)
DAVCollection.__init__(self, path, environ)
self._sid = environ["wsgidav.auth.user_name"]
config = TextgridConfig()
config = tg_config(environ)
self._tgsearch = TextgridSearch(config.search)
self._project_id = self.path.split("/")[-1]
......@@ -175,7 +186,7 @@ class TextgridAggregation(DAVCollection):
DAVCollection.__init__(self, path, environ)
self._sid = environ["wsgidav.auth.user_name"]
self._info = info
config = TextgridConfig()
config = tg_config(environ)
self._tgsearch = TextgridSearch(config.search)
self._tguri = self.path.split("/")[-1]
......@@ -261,7 +272,7 @@ class TextgridResource(DAVNonCollection):
self._tguri = self.path.split("/")[-1]
self._info = info
self.upload_thread = None
config = TextgridConfig()
config = tg_config(environ)
self._crud = TextgridCRUD(config.crud)
def get_content_length(self):
......@@ -273,7 +284,9 @@ class TextgridResource(DAVNonCollection):
return self._info[self.name]["format"]
def get_content(self):
_logger.debug("Called TextgridResource.get_content(self) with path: %s", self.path)
_logger.debug(
"Called TextgridResource.get_content(self) with path: %s", self.path
)
return io.BytesIO(self._crud.read_data(self._tguri, self._sid).content)
def get_content_title(self):
......