diff --git a/.gitignore b/.gitignore
index aa73ebb11..ce36a8619 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,6 +59,7 @@ scripts/keycloak/data/*
# ignore clowder chart deps
deployments/kubernetes/charts/clowder2/charts
deployments/kubernetes/charts/clowder2/*clowder2-software-dev.yaml
+*secret*.yaml
# Environments
.env
diff --git a/.run/Python tests in tests.run.xml b/.run/Python tests in tests.run.xml
index 2fd8345de..2f33fbef9 100644
--- a/.run/Python tests in tests.run.xml
+++ b/.run/Python tests in tests.run.xml
@@ -3,9 +3,10 @@
-
+
+
-
+
@@ -14,4 +15,4 @@
-
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a2d26d27..90a2ab48c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [v2.0.0-beta.3] - 2024-07-29
+
+### Added
+
+- License management
+- Release dataset with versions
+- Enable and disable user account through Keycloak
+- Jupyterhub integration
+- Interface for creating and editing matching criteria for triggering extractors
+- Interface for editing metadata definitions
+- My dataset tab listing all the datasets created by the user
+- Drag and drop upload multiple files
+- Footer with links to documentation, source code, and contact information
+- Documentation through MKDocs
+
+### Changed
+
+- Allow public datasets and files to be searchable
+- List all the extractors with the ability to enable/disable the extractors
+- Filter listeners based on their support for file or dataset
+- Helm chart updated to support custom existing secret
+
+### Fixed
+
+- Clowder registration link on the top bar
+- Case-insensitive search
+- Download count immediately increments after download
+
## [v2.0.0-beta.2] - 2024-02-16
### Added
diff --git a/backend/app/config.py b/backend/app/config.py
index 2f3041853..ae88e43d3 100644
--- a/backend/app/config.py
+++ b/backend/app/config.py
@@ -9,7 +9,7 @@ class Settings(BaseSettings):
API_V2_STR: str = "/api/v2"
admin_email: str = "devnull@ncsa.illinois.edu"
frontend_url: str = "http://localhost:3000"
- version: str = "2.0.0-beta.2"
+ version: str = "2.0.0-beta.3"
# Unique secret for hashing API keys. Generate with `openssl rand -hex 32`
local_auth_secret = "clowder_secret_key"
diff --git a/backend/app/main.py b/backend/app/main.py
index 84f54d38b..564ed7726 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -26,6 +26,7 @@
MetadataDefinitionDB,
MetadataFreezeDB,
)
+from app.models.project import ProjectDB
from app.models.thumbnails import ThumbnailDB, ThumbnailDBViewList, ThumbnailFreezeDB
from app.models.tokens import TokenDB
from app.models.users import ListenerAPIKeyDB, UserAPIKeyDB, UserDB
@@ -55,6 +56,7 @@
metadata,
metadata_datasets,
metadata_files,
+ projects,
public_datasets,
public_elasticsearch,
public_files,
@@ -86,7 +88,7 @@
description="A cloud native data management framework to support any research domain. Clowder was "
"developed to help researchers and scientists in data intensive domains manage raw data, complex "
"metadata, and automatic data pipelines. ",
- version="2.0.0-beta.2",
+ version="2.0.0-beta.3",
contact={"name": "Clowder", "url": "https://clowderframework.org/"},
license_info={
"name": "Apache 2.0",
@@ -250,6 +252,11 @@
prefix="/public_thumbnails",
tags=["public_thumbnails"],
)
+api_router.include_router(
+ projects.router,
+ prefix="/projects",
+ tags=["projects"],
+)
api_router.include_router(
licenses.router,
prefix="/licenses",
@@ -315,6 +322,7 @@ async def startup_beanie():
ThumbnailFreezeDB,
ThumbnailDBViewList,
LicenseDB,
+ ProjectDB,
],
recreate_views=True,
)
diff --git a/backend/app/models/project.py b/backend/app/models/project.py
new file mode 100644
index 000000000..8239847ed
--- /dev/null
+++ b/backend/app/models/project.py
@@ -0,0 +1,42 @@
+from datetime import datetime
+from enum import Enum, auto
+from typing import List, Optional
+
+import pymongo
+from app.models.authorization import AuthorizationDB, RoleType
+from app.models.groups import GroupOut
+from app.models.users import UserOut
+from beanie import Document, PydanticObjectId, View
+from pydantic import BaseModel, Field
+
+
+class Member(BaseModel):
+ user: UserOut
+ editor: bool = False
+
+
+class ProjectBase(BaseModel):
+ id: PydanticObjectId = Field(default_factory=PydanticObjectId, alias="_id")
+ name: str
+ description: Optional[str] = None
+ created: datetime = Field(default_factory=datetime.utcnow)
+ modified: datetime = Field(default_factory=datetime.utcnow)
+ dataset_ids: Optional[List[PydanticObjectId]] = []
+ folder_ids: Optional[List[PydanticObjectId]] = []
+ file_ids: Optional[List[PydanticObjectId]] = []
+ creator: UserOut
+ users: List[Member] = []
+
+
+class ProjectDB(Document, ProjectBase):
+ class Settings:
+ name = "projects"
+
+
+class ProjectIn(ProjectBase):
+ pass
+
+
+class ProjectOut(ProjectDB):
+ class Config:
+ fields = {"id": "id"}
diff --git a/backend/app/routers/projects.py b/backend/app/routers/projects.py
new file mode 100644
index 000000000..135a6da91
--- /dev/null
+++ b/backend/app/routers/projects.py
@@ -0,0 +1,319 @@
+import datetime
+import hashlib
+import io
+import os
+import shutil
+import tempfile
+import zipfile
+from collections.abc import Iterable, Mapping
+from typing import List, Optional
+
+from app import dependencies
+from app.config import settings
+from app.keycloak_auth import get_current_user, get_token, get_user
+from app.models.datasets import DatasetDB
+from app.models.files import FileDB
+from app.models.folders import FolderDB
+from app.models.pages import Paged, _construct_page_metadata, _get_page_query
+from app.models.project import Member, ProjectBase, ProjectDB, ProjectIn, ProjectOut
+from app.models.users import UserDB, UserIn, UserOut
+from beanie import PydanticObjectId
+from beanie.operators import And, Or
+from bson import ObjectId, json_util
+from elasticsearch import Elasticsearch
+from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile
+from fastapi.responses import StreamingResponse
+from fastapi.security import HTTPBearer
+from minio import Minio
+from pika.adapters.blocking_connection import BlockingChannel
+from pymongo import DESCENDING
+from rocrate.model.person import Person
+from rocrate.rocrate import ROCrate
+
+router = APIRouter()
+security = HTTPBearer()
+
+clowder_bucket = os.getenv("MINIO_BUCKET_NAME", "clowder")
+
+
+@router.post("", response_model=ProjectOut)
+async def save_project(
+ project_in: ProjectIn,
+ user=Depends(get_current_user),
+ es: Elasticsearch = Depends(dependencies.get_elasticsearchclient),
+):
+ project = ProjectDB(**project_in.dict())
+ await project.insert()
+
+ # TODO Add new entry to elasticsearch
+ return project.dict()
+
+
+@router.post("/{project_id}/add_dataset/{dataset_id}", response_model=ProjectOut)
+async def add_dataset(
+ project_id: str,
+ dataset_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ if (
+ dataset := await DatasetDB.find_one(
+ Or(
+ DatasetDB.id == PydanticObjectId(dataset_id),
+ )
+ )
+ ) is not None:
+ if dataset_id not in project.dataset_ids:
+ project.dataset_ids.append(PydanticObjectId(dataset_id))
+ await project.replace()
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Dataset {dataset_id} not found")
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.post("/{project_id}/remove_dataset/{dataset_id}", response_model=ProjectOut)
+async def remove_dataset(
+ project_id: str,
+ dataset_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ if (
+ dataset := await DatasetDB.find_one(
+ Or(
+ DatasetDB.id == PydanticObjectId(dataset_id),
+ )
+ )
+ ) is not None:
+ if dataset_id in project.dataset_ids:
+ project.dataset_ids.remove(PydanticObjectId(dataset_id))
+ await project.replace()
+ return project.dict()
+ else:
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Dataset {dataset_id} not found")
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.post("/{project_id}/add_folder/{folder_id}", response_model=ProjectOut)
+async def add_folder(
+ project_id: str,
+ folder_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ if (
+ folder := await FolderDB.find_one(
+ Or(
+ FolderDB.id == FolderDB(PydanticObjectId(folder_id)),
+ )
+ )
+ ) is not None:
+ if folder_id not in project.folder_ids:
+ project.folder_ids.append(PydanticObjectId(folder_id))
+ await project.replace()
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Folder {folder_id} not found")
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.post("/{project_id}/remove_folder/{folder_id}", response_model=ProjectOut)
+async def remove_folder(
+ project_id: str,
+ folder_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ if (
+ folder := await FolderDB.find_one(
+ Or(
+ FolderDB.id == FolderDB(PydanticObjectId(folder_id)),
+ )
+ )
+ ) is not None:
+ if folder_id in project.folder_ids:
+ project.folder_ids.remove(PydanticObjectId(folder_id))
+ await project.replace()
+ return project.dict()
+ else:
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Folder {folder_id} not found")
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.post("/{project_id}/add_file/{file_id}", response_model=ProjectOut)
+async def add_file(
+ project_id: str,
+ file_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ if (
+ file := await FolderDB.find_one(
+ Or(
+ FileDB.id == FileDB(PydanticObjectId(file_id)),
+ )
+ )
+ ) is not None:
+ if file_id not in project.file_ids:
+ project.file_ids.append(PydanticObjectId(file_id))
+ await project.replace()
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"File {file_id} not found")
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.post("/{project_id}/remove_file/{file_id}", response_model=ProjectOut)
+async def remove_file(
+ project_id: str,
+ file_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ if (
+ file := await FolderDB.find_one(
+ Or(
+ FileDB.id == FileDB(PydanticObjectId(file_id)),
+ )
+ )
+ ) is not None:
+ if file_id in project.file_ids:
+ project.file_ids.remove(PydanticObjectId(file_id))
+ await project.replace()
+ return project.dict()
+ else:
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"File {file_id} not found")
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.get("", response_model=Paged)
+async def get_projects(
+ user_id=Depends(get_user),
+ skip: int = 0,
+ limit: int = 10,
+ mine: bool = False,
+ enable_admin: bool = False,
+):
+ # TODO check if the current user is a member OR creator
+ projects_and_count = await ProjectDB.aggregate(
+ [_get_page_query(skip, limit, sort_field="email", ascending=True)],
+ ).to_list()
+
+ page_metadata = _construct_page_metadata(projects_and_count, skip, limit)
+ # TODO have to change _id this way otherwise it won't work
+ # TODO need to research if there is other pydantic trick to make it work
+
+ page = Paged(
+ metadata=page_metadata,
+ data=[
+ ProjectOut(id=item.pop("_id"), **item)
+ for item in projects_and_count[0]["data"]
+ ],
+ )
+
+ return page.dict()
+
+
+@router.get("/{project_id}", response_model=ProjectOut)
+async def get_project(
+ project_id: str,
+):
+ if (
+ project := await ProjectDB.find_one(
+ Or(
+ ProjectDB.id == PydanticObjectId(project_id),
+ )
+ )
+ ) is not None:
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.delete("/{project_id}", response_model=ProjectOut)
+async def delete_project(
+ project_id: str,
+):
+ if (project := await ProjectDB.get(PydanticObjectId(project_id))) is not None:
+ await project.delete()
+ return project.dict() # TODO: Do we need to return what we just deleted?
+ else:
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+
+
+@router.post("/{project_id}/add_member/{username}", response_model=ProjectOut)
+async def add_member(
+ project_id: str,
+ username: str,
+ role: Optional[str] = None,
+):
+ """Add a new user to a group."""
+ if (user := await UserDB.find_one(UserDB.email == username)) is not None:
+ new_member = Member(user=UserOut(**user.dict()))
+ if (project := await ProjectDB.get(PydanticObjectId(project_id))) is not None:
+ found_already = False
+ for u in project.users:
+ if u.user.email == username:
+ found_already = True
+ break
+ if not found_already:
+ # If user is already in the group, skip directly to returning the group
+ # else add role and attach this member
+ project.users.append(new_member)
+ await project.replace()
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
+ raise HTTPException(status_code=404, detail=f"User {username} not found")
+
+
+@router.post("/{project_id}/remove_member/{username}", response_model=ProjectOut)
+async def remove_member(
+ project_id: str,
+ username: str,
+):
+ """Remove a user from a group."""
+
+ if (project := await ProjectDB.get(PydanticObjectId(project_id))) is not None:
+ # Is the user actually in the group already?
+ found_user = None
+ for u in project.users:
+ if u.user.email == username:
+ found_user = u
+ if not found_user:
+ # TODO: User wasn't in group, should this throw an error instead? Either way, the user is removed...
+ return project
+ # Update group itself
+ project.users.remove(found_user)
+ await project.replace()
+ return project.dict()
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
diff --git a/backend/app/tests/test_projects.py b/backend/app/tests/test_projects.py
new file mode 100644
index 000000000..3d4e5000d
--- /dev/null
+++ b/backend/app/tests/test_projects.py
@@ -0,0 +1,67 @@
+from app.config import settings
+from app.tests.utils import (
+ create_dataset,
+ create_group,
+ create_project,
+ create_user,
+ get_user_token,
+ user_alt,
+)
+from fastapi.testclient import TestClient
+
+member_alt = {"user": user_alt, "editor": False}
+
+
+def test_create_project(client: TestClient, headers: dict):
+ create_project(client, headers)
+
+
+def test_get_project(client: TestClient, headers: dict):
+ project_id = create_project(client, headers).get("id")
+ response = client.get(
+ f"{settings.API_V2_STR}/projects/{project_id}", headers=headers
+ )
+ assert response.status_code == 200
+ assert response.json().get("id") is not None
+
+
+def test_delete_project(client: TestClient, headers: dict):
+ project_id = create_project(client, headers).get("id")
+ response = client.delete(
+ f"{settings.API_V2_STR}/projects/{project_id}", headers=headers
+ )
+ assert response.status_code == 200
+
+
+def test_add_member(client: TestClient, headers: dict):
+ new_project = create_project(client, headers)
+ project_id = new_project.get("id")
+
+ create_user(client, headers)
+ new_project["users"].append(member_alt)
+
+ response = client.post(
+ f"{settings.API_V2_STR}/projects/{project_id}/add_member/{member_alt['user']['email']}",
+ headers=headers,
+ )
+
+ assert response.status_code == 200
+ assert response.json().get("id") is not None
+ for user in response.json().get("users"):
+ assert user.get("user").get("email") == member_alt["user"]["email"]
+
+
+def test_add_dataset(client: TestClient, headers: dict):
+ new_project = create_project(client, headers)
+ project_id = new_project.get("id")
+
+ dataset_id = create_dataset(client, headers).get("id")
+
+ response = client.post(
+ f"{settings.API_V2_STR}/projects/{project_id}/add_dataset/{dataset_id}",
+ headers=headers,
+ )
+
+ assert response.status_code == 200
+ assert response.json().get("id") is not None
+ assert dataset_id in response.json().get("dataset_ids")
diff --git a/backend/app/tests/utils.py b/backend/app/tests/utils.py
index 395d2a676..059718890 100644
--- a/backend/app/tests/utils.py
+++ b/backend/app/tests/utils.py
@@ -61,6 +61,12 @@
},
}
+project_example = {
+ "name": "test_project",
+ "description": "This project is a test",
+ "creator": user_example,
+}
+
extractor_info_v1_example = {
"@context": "http://clowder.ncsa.illinois.edu/contexts/extractors.jsonld",
"name": "test.extractor_info_v1_example",
@@ -176,6 +182,18 @@ def create_dataset_with_custom_license(client: TestClient, headers: dict):
return response.json()
+def create_project(client: TestClient, headers: dict):
+ """Creates a test dataset and returns the JSON."""
+ response = client.post(
+ f"{settings.API_V2_STR}/projects",
+ headers=headers,
+ json=project_example,
+ )
+ assert response.status_code == 200
+ assert response.json().get("id") is not None
+ return response.json()
+
+
def upload_file(
client: TestClient,
headers: dict,
diff --git a/deployments/kubernetes/charts/clowder2/Chart.yaml b/deployments/kubernetes/charts/clowder2/Chart.yaml
index dabacef56..fea872e94 100644
--- a/deployments/kubernetes/charts/clowder2/Chart.yaml
+++ b/deployments/kubernetes/charts/clowder2/Chart.yaml
@@ -13,13 +13,13 @@ description: >
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 1.9.1
+version: 1.9.2
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
-appVersion: "2.0.0-beta.2"
+appVersion: "2.0.0-beta.3"
# List of people that maintain this helm chart.
maintainers:
diff --git a/deployments/kubernetes/charts/clowder2/README.md b/deployments/kubernetes/charts/clowder2/README.md
index 76f43513e..0f7c69768 100644
--- a/deployments/kubernetes/charts/clowder2/README.md
+++ b/deployments/kubernetes/charts/clowder2/README.md
@@ -17,13 +17,13 @@ hostname: { your hostname. E.g. clowder2.software-dev.ncsa.illinois.edu }
frontend:
image:
repository: clowder/clowder2-frontend
- tag: 2.0.0-beta.2
+ tag: 2.0.0-beta.3
pullPolicy: Always
backend:
image:
repository: clowder/clowder2-backend
- tag: 2.0.0-beta.2
+ tag: 2.0.0-beta.3
pullPolicy: Always
geoserver:
diff --git a/deployments/kubernetes/charts/clowder2/templates/NOTES.txt b/deployments/kubernetes/charts/clowder2/templates/NOTES.txt
index e0dfa09a9..8ba1c1c8a 100644
--- a/deployments/kubernetes/charts/clowder2/templates/NOTES.txt
+++ b/deployments/kubernetes/charts/clowder2/templates/NOTES.txt
@@ -15,7 +15,7 @@
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "clowder2.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.frontend.service.port }}
{{- else if contains "ClusterIP" .Values.frontend.service.type }}
- export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "clowder2.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "clowder2.fullname" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
diff --git a/deployments/kubernetes/charts/clowder2/templates/_helpers.tpl b/deployments/kubernetes/charts/clowder2/templates/_helpers.tpl
index da435e845..49cbaa634 100644
--- a/deployments/kubernetes/charts/clowder2/templates/_helpers.tpl
+++ b/deployments/kubernetes/charts/clowder2/templates/_helpers.tpl
@@ -46,7 +46,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }}
Selector labels
*/}}
{{- define "clowder2.selectorLabels" -}}
-app.kubernetes.io/name: {{ include "clowder2.name" . }}
+app.kubernetes.io/name: {{ include "clowder2.fullname" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
diff --git a/deployments/kubernetes/charts/clowder2/templates/backend/deployment.yaml b/deployments/kubernetes/charts/clowder2/templates/backend/deployment.yaml
index 988fc536c..4daa2a606 100644
--- a/deployments/kubernetes/charts/clowder2/templates/backend/deployment.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/backend/deployment.yaml
@@ -10,7 +10,7 @@ spec:
{{- end }}
selector:
matchLabels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-backend
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-backend
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
@@ -19,7 +19,7 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-backend
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-backend
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- with .Values.imagePullSecrets }}
@@ -39,25 +39,31 @@ spec:
- name: WEB_CONCURRENCY
value: "1"
- name: MINIO_SERVER_URL
- value: {{ include "clowder2.name" . }}-minio:9000
-# value: {{ include "clowder2.name" . }}-minio-headless:9000
+ value: {{ .Values.backend.env.MINIO_SERVER_URL }}
- name: MINIO_EXTERNAL_SERVER_URL
value: minio-api.{{ .Values.hostname }}
- name: MINIO_SECURE
- value: "true"
+ value: {{ .Values.backend.env.MINIO_SECURE | quote }}
- name: MINIO_BUCKET_NAME
- value: clowder
+ value: {{ .Values.backend.env.MINIO_BUCKET_NAME }}
- name: MINIO_ACCESS_KEY
value: {{ .Values.minio.auth.rootUser }}
- name: MINIO_SECRET_KEY
+ {{- if .Values.backend.existingSecret }}
valueFrom:
secretKeyRef:
- name: clowder2-minio
+ name: {{ .Values.backend.existingSecret }}
+ key: {{ .Values.backend.existingMinioSecretKey | default "root-password" }}
+ {{- else }}
+ valueFrom:
+ secretKeyRef:
+ name: {{ include "clowder2.fullname" . }}-minio
key: root-password
+ {{- end }}
- name: MINIO_UPLOAD_CHUNK_SIZE
- value: "10485760"
+ value: {{ .Values.backend.env.MINIO_UPLOAD_CHUNK_SIZE | quote}}
- name: MONGODB_URL
- value: mongodb://{{ include "clowder2.name" . }}-mongodb:27017
+ value: {{ .Values.backend.env.MONGODB_URL }}
- name: MONGO_DATABASE
value: {{ .Values.mongodb.database }}
- name: CLOWDER2_URL
@@ -73,11 +79,11 @@ spec:
- name: auth_url
value: $(CLOWDER2_URL)/keycloak/realms/clowder/protocol/openid-connect/auth?client_id=clowder2-backend&response_type=code
- name: oauth2_scheme_auth_url
- value: http://{{ include "clowder2.name" .}}-keycloak-headless:8080/keycloak/realms/clowder/protocol/openid-connect/auth?client_id=clowder2-backend&response_type=code
+ value: {{ .Values.backend.env.oauth2_scheme_auth_url }}
- name: auth_register_url
- value: $(CLOWDER2_URL)/keycloak/realms/clowder/protocol/openid-connect/registrations?client_id=clowder2-backend&response_type=code&redirect_uri=$(auth_redirect_uri)&scope=openid%20email
+ value: $(CLOWDER2_URL){{ .Values.backend.env.auth_register_url }}
- name: auth_token_url
- value: http://{{ include "clowder2.name" .}}-keycloak-headless:8080/keycloak/realms/clowder/protocol/openid-connect/token
+ value: {{ .Values.backend.env.auth_token_url }}
- name: auth_server_url
value: $(CLOWDER2_URL)/keycloak/
- name: keycloak_base
@@ -85,7 +91,7 @@ spec:
- name: frontend_url
value: $(CLOWDER2_URL)
- name: elasticsearch_url
- value: http://{{ include "clowder2.name" . }}-elasticsearch:9200
+ value: {{ .Values.backend.env.elasticsearch_url }}
- name: elasticsearch_no_of_shards
value: "5"
- name: elasticsearch_no_of_replicas
@@ -93,17 +99,23 @@ spec:
- name: RABBITMQ_USER
value: {{ .Values.rabbitmq.auth.username }}
- name: RABBITMQ_PASS
+ {{- if .Values.backend.existingSecret }}
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.backend.existingSecret }}
+ key: {{ .Values.backend.existingRabbitMQSecretKey | default "rabbitmq-password" }}
+ {{- else }}
valueFrom:
secretKeyRef:
- name: clowder2-rabbitmq
+ name: {{ include "clowder2.fullname" . }}-rabbitmq
key: rabbitmq-password
+ {{- end }}
- name: RABBITMQ_HOST
- value: {{ include "clowder2.name" . }}-rabbitmq
+ value: {{ .Values.backend.env.RABBITMQ_HOST }}
- name: HEARTBEAT_EXCHANGE
value: "extractors"
- name: API_HOST
-# value: $(CLOWDER2_URL)
- value: http://{{ include "clowder2.name" . }}-backend:{{ .Values.backend.service.port }}
+ value: {{ .Values.backend.env.API_HOST }}
ports:
- name: http
containerPort: 80
diff --git a/deployments/kubernetes/charts/clowder2/templates/backend/ingress.yaml b/deployments/kubernetes/charts/clowder2/templates/backend/ingress.yaml
index 41423cc31..0b7ddec6b 100644
--- a/deployments/kubernetes/charts/clowder2/templates/backend/ingress.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/backend/ingress.yaml
@@ -21,7 +21,6 @@ spec:
{{- if .Values.ingress.tls }}
tls:
- hosts:
- - {{ .Values.hostname }}
{{- range .Values.ingress.tls }}
{{- range .hosts }}
- {{ . | quote }}
diff --git a/deployments/kubernetes/charts/clowder2/templates/extractors/deployment.yaml b/deployments/kubernetes/charts/clowder2/templates/extractors/deployment.yaml
index ab055b7c7..7d9c4babb 100644
--- a/deployments/kubernetes/charts/clowder2/templates/extractors/deployment.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/extractors/deployment.yaml
@@ -38,10 +38,17 @@ spec:
- name: RABBITMQ_USER
value: {{ $.Values.rabbitmq.auth.username }}
- name: RABBITMQ_PASS
+ {{- if $val.existingSecret }}
valueFrom:
secretKeyRef:
- name: clowder2-rabbitmq
+ name: {{ $val.existingSecret }}
+ key: {{ $val.existingRabbitMQSecretKey | default "rabbitmq-password" }}
+ {{- else }}
+ valueFrom:
+ secretKeyRef:
+ name: {{ $fullname }}-rabbitmq
key: rabbitmq-password
+ {{- end }}
- name: CLOWDER_VERSION
value: "2"
- name: RABBITMQ_URI
diff --git a/deployments/kubernetes/charts/clowder2/templates/frontend/deployment.yaml b/deployments/kubernetes/charts/clowder2/templates/frontend/deployment.yaml
index eab44f6be..51cb9ca6c 100644
--- a/deployments/kubernetes/charts/clowder2/templates/frontend/deployment.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/frontend/deployment.yaml
@@ -10,7 +10,7 @@ spec:
{{- end }}
selector:
matchLabels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-frontend
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-frontend
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
@@ -19,7 +19,7 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-frontend
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-frontend
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- with .Values.imagePullSecrets }}
diff --git a/deployments/kubernetes/charts/clowder2/templates/frontend/ingress.yaml b/deployments/kubernetes/charts/clowder2/templates/frontend/ingress.yaml
index dde70f74c..f54044a36 100644
--- a/deployments/kubernetes/charts/clowder2/templates/frontend/ingress.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/frontend/ingress.yaml
@@ -21,7 +21,6 @@ spec:
{{- if .Values.ingress.tls }}
tls:
- hosts:
- - {{ .Values.hostname }}
{{- range .Values.ingress.tls }}
{{- range .hosts }}
- {{ . | quote }}
diff --git a/deployments/kubernetes/charts/clowder2/templates/geoserver/deployment.yaml b/deployments/kubernetes/charts/clowder2/templates/geoserver/deployment.yaml
index 2a97c6ac1..7ee3a45da 100644
--- a/deployments/kubernetes/charts/clowder2/templates/geoserver/deployment.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/geoserver/deployment.yaml
@@ -9,14 +9,14 @@ spec:
replicas: {{ .Values.geoserver.replicaCount }}
selector:
matchLabels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-geoserver
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-geoserver
app.kubernetes.io/instance: {{ .Release.Name }}
strategy:
type: RollingUpdate
template:
metadata:
labels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-geoserver
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-geoserver
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- with .Values.imagePullSecrets }}
@@ -29,15 +29,19 @@ spec:
imagePullPolicy: {{ .Values.geoserver.image.pullPolicy }}
env:
- name: GEOSERVER_ADMIN_USER
+ value: {{ .Values.geoserver.username }}
+ - name: GEOSERVER_ADMIN_PASSWORD
+ {{- if .Values.geoserver.existingSecret }}
valueFrom:
secretKeyRef:
- name: {{ include "clowder2.fullname" . }}-services
- key: GEOSERVER_USER
- - name: GEOSERVER_ADMIN_PASSWORD
+ name: {{.Values.geoserver.existingSecret }}
+ key: {{.Values.geoserver.existingGeoserverSecretKey | default "GEOSERVER_PW" }}
+ {{- else }}
valueFrom:
secretKeyRef:
- name: {{ include "clowder2.fullname" . }}-services
+ name: {{include "clowder2.fullname" . }}-services
key: GEOSERVER_PW
+ {{- end }}
ports:
- containerPort: 8080
name: geoserver
diff --git a/deployments/kubernetes/charts/clowder2/templates/geoserver/service.yaml b/deployments/kubernetes/charts/clowder2/templates/geoserver/service.yaml
index 3a967f618..83e341cb0 100644
--- a/deployments/kubernetes/charts/clowder2/templates/geoserver/service.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/geoserver/service.yaml
@@ -13,6 +13,6 @@ spec:
targetPort: geoserver
protocol: TCP
selector:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-geoserver
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-geoserver
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
diff --git a/deployments/kubernetes/charts/clowder2/templates/heartbeat/deployment.yaml b/deployments/kubernetes/charts/clowder2/templates/heartbeat/deployment.yaml
index a2f53a69d..44dea9954 100644
--- a/deployments/kubernetes/charts/clowder2/templates/heartbeat/deployment.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/heartbeat/deployment.yaml
@@ -10,7 +10,7 @@ spec:
{{- end }}
selector:
matchLabels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-heartbeat
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-heartbeat
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
@@ -19,7 +19,7 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-heartbeat
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-heartbeat
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- with .Values.imagePullSecrets }}
@@ -34,16 +34,23 @@ spec:
imagePullPolicy: {{ .Values.heartbeat.image.pullPolicy }}
env:
- name: MONGODB_URL
- value: mongodb://{{ include "clowder2.name" . }}-mongodb:27017
+ value: {{ .Values.heartbeat.env.MONGODB_URL }}
- name: RABBITMQ_USER
value: {{ .Values.rabbitmq.auth.username }}
- name: RABBITMQ_PASS
+ {{- if .Values.heartbeat.existingSecret }}
valueFrom:
secretKeyRef:
- name: clowder2-rabbitmq
+ name: {{.Values.heartbeat.existingSecret }}
+ key: {{.Values.heartbeat.existingRabbitMQSecretKey | default "rabbitmq-password" }}
+ {{- else }}
+ valueFrom:
+ secretKeyRef:
+ name: {{include "clowder2.fullname" . }}-rabbitmq
key: rabbitmq-password
+ {{- end }}
- name: RABBITMQ_HOST
- value: {{ include "clowder2.name" . }}-rabbitmq
+ value: {{ .Values.heartbeat.env.RABBITMQ_HOST }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
diff --git a/deployments/kubernetes/charts/clowder2/templates/messages/deployment.yaml b/deployments/kubernetes/charts/clowder2/templates/messages/deployment.yaml
index 680bd1cd3..d85dfde00 100644
--- a/deployments/kubernetes/charts/clowder2/templates/messages/deployment.yaml
+++ b/deployments/kubernetes/charts/clowder2/templates/messages/deployment.yaml
@@ -10,7 +10,7 @@ spec:
{{- end }}
selector:
matchLabels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-messages
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-messages
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
@@ -19,7 +19,7 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
- app.kubernetes.io/name: {{ include "clowder2.name" . }}-messages
+ app.kubernetes.io/name: {{ include "clowder2.fullname" . }}-messages
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- with .Values.imagePullSecrets }}
@@ -34,16 +34,23 @@ spec:
imagePullPolicy: {{ .Values.message.image.pullPolicy }}
env:
- name: MONGODB_URL
- value: mongodb://{{ include "clowder2.name" . }}-mongodb:27017
+ value: {{ .Values.message.env.MONGODB_URL }}
- name: RABBITMQ_USER
value: {{ .Values.rabbitmq.auth.username }}
- name: RABBITMQ_PASS
+ {{- if .Values.message.existingSecret }}
valueFrom:
secretKeyRef:
- name: clowder2-rabbitmq
+ name: {{ .Values.message.existingSecret }}
+ key: {{ .Values.message.existingRabbitMQSecretKey | default "rabbitmq-password" }}
+ {{- else }}
+ valueFrom:
+ secretKeyRef:
+ name: {{ include "clowder2.fullname" . }}-rabbitmq
key: rabbitmq-password
+ {{- end }}
- name: RABBITMQ_HOST
- value: {{ include "clowder2.name" . }}-rabbitmq
+ value: {{ .Values.message.env.RABBITMQ_HOST }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
diff --git a/deployments/kubernetes/charts/clowder2/values.yaml b/deployments/kubernetes/charts/clowder2/values.yaml
index 262aea520..a09fc20f4 100644
--- a/deployments/kubernetes/charts/clowder2/values.yaml
+++ b/deployments/kubernetes/charts/clowder2/values.yaml
@@ -51,7 +51,18 @@ backend:
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
-
+ env:
+ MINIO_SERVER_URL: clowder2-minio:9000
+ MINIO_SECURE: "true"
+ MINIO_UPLOAD_CHUNK_SIZE: "10485760"
+ MINIO_BUCKET_NAME: clowder
+ MONGODB_URL: mongodb://clowder2-mongodb:27017
+ oauth2_scheme_auth_url: http://clowder2-keycloak-headless:8080/keycloak/realms/clowder/protocol/openid-connect/auth?client_id=clowder2-backend&response_type=code
+ auth_register_url: /keycloak/realms/clowder/protocol/openid-connect/registrations?client_id=clowder2-backend&response_type=code&redirect_uri=$(auth_redirect_uri)&scope=openid%20email
+ auth_token_url: http://clowder2-keycloak-headless:8080/keycloak/realms/clowder/protocol/openid-connect/token
+ elasticsearch_url: http://clowder2-elasticsearch:9200
+ RABBITMQ_HOST: clowder2-rabbitmq
+ API_HOST: http://clowder2-backend:80
service:
type: ClusterIP
port: 80
@@ -60,7 +71,7 @@ backend:
# GEOSERVER
# ----------------------------------------------------------------------
geoserver:
- enabled : true
+ enabled : false
username: admin
password: admin
workspace: clowder2
@@ -97,12 +108,12 @@ minio:
# enable ingress for webui
ingress:
- enabled: true
+ enabled: false
hostname: minio.clowder2.localhost
# enable ingress for api
apiIngress:
- enabled: true
+ enabled: false
hostname: minio-api.clowder2.localhost
# enabled distributed mode (or standalone)
@@ -165,7 +176,7 @@ rabbitmq:
# enable webfrontend
ingress:
- enabled: true
+ enabled: false
hostname: rabbitmq.clowder2.localhost
persistence:
@@ -175,40 +186,51 @@ rabbitmq:
# ----------------------------------------------------------------------
# DEFAULT EXTRACTOR SERVICES
# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# EXTRACTORS
message:
image:
repository: clowder/clowder2-messages
-# tag: main
pullPolicy: Always
+ env:
+ MONGODB_URL: mongodb://clowder2-mongodb:27017
+ RABBITMQ_HOST: clowder2-rabbitmq
heartbeat:
image:
repository: clowder/clowder2-heartbeat
-# tag: main
pullPolicy: Always
+ env:
+ MONGODB_URL: mongodb://clowder2-mongodb:27017
+ RABBITMQ_HOST: clowder2-rabbitmq
-
-# ----------------------------------------------------------------------
-# EXTRACTORS
-# ----------------------------------------------------------------------
## list of extractors to be installed. Each extractor should have the
## following fields:
## enabled : true/false - should the extractor be installed
## image : dokeer/image:tag - the extractor docker image
## replicaCount : number - the number of this extractor to install
## env : additional environment variables to pass to extractor.
+
extractors:
wordcount:
+ enabled: false
image: clowder/extractors-wordcount:latest
image-preview:
+ enabled: false
image: clowder/extractors-image-preview:latest
image-metadata:
+ enabled: false
image: clowder/extractors-image-metadata:latest
audio-preview:
+ enabled: false
image: clowder/extractors-audio-preview:latest
file-digest:
+ enabled: false
image: clowder/extractors-digest:latest
geotiff-preview:
+ enabled: false
image: clowder/extractors-geotiff-preview:latest
# ----------------------------------------------------------------------
diff --git a/docker-compose.yml b/docker-compose.yml
index f74ad11b6..348757c2e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -37,7 +37,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
backend:
- image: 'clowder/clowder2-backend:2.0.0-beta.2'
+ image: 'clowder/clowder2-backend:2.0.0-beta.3'
restart: unless-stopped
build:
context: ./backend
@@ -77,7 +77,7 @@ services:
- "traefik.http.routers.backend.priority=5"
frontend:
- image: "clowder/clowder2-frontend:2.0.0-beta.2"
+ image: "clowder/clowder2-frontend:2.0.0-beta.3"
restart: unless-stopped
build:
context: ./frontend
diff --git a/docs/docs/admins/backups.md b/docs/docs/admins/backups.md
index 8c0c04ce2..299adae3a 100644
--- a/docs/docs/admins/backups.md
+++ b/docs/docs/admins/backups.md
@@ -1 +1 @@
-# Backups
\ No newline at end of file
+# Backups
diff --git a/docs/docs/admins/config.md b/docs/docs/admins/config.md
index 0a7b1bd35..3891e38a8 100644
--- a/docs/docs/admins/config.md
+++ b/docs/docs/admins/config.md
@@ -3,4 +3,4 @@
Each instance of Clowder can be configured at deployment time using the config file. The config file is located
in `backend/app/config.py`. At run time, environmental variables passed into the container will override the defaults
in the config file. When using Docker Compose, the environmental variables are set in the `docker-compose.yml` file or
-in `.env` file. In the case of Kubernetes, the environmental variables are set in the `values.yaml` file.
\ No newline at end of file
+in `.env` file. In the case of Kubernetes, the environmental variables are set in the `values.yaml` file.
diff --git a/docs/docs/devs/architecture.md b/docs/docs/devs/architecture.md
index 392b8fd8f..3c2046bdf 100644
--- a/docs/docs/devs/architecture.md
+++ b/docs/docs/devs/architecture.md
@@ -10,9 +10,9 @@ Lines show interactions between containers over the docker network.

Architecture
-I want to `slkdfjslkdjf` include a
+I want to `slkdfjslkdjf` include a
- alkdjflskjdf
- alskdjflksajfd
- [slkjdf](http://clowder.com)
- -
+ -
diff --git a/docs/docs/devs/frontend/lazyloading.md b/docs/docs/devs/frontend/lazyloading.md
index 5653e63fc..14d0ed1dd 100644
--- a/docs/docs/devs/frontend/lazyloading.md
+++ b/docs/docs/devs/frontend/lazyloading.md
@@ -1 +1 @@
-# Webpack Lazy Loading
\ No newline at end of file
+# Webpack Lazy Loading
diff --git a/docs/docs/devs/precommits.md b/docs/docs/devs/precommits.md
index 5c559b681..3a780a802 100644
--- a/docs/docs/devs/precommits.md
+++ b/docs/docs/devs/precommits.md
@@ -1,2 +1 @@
# Precommits and Linting
-
diff --git a/docs/docs/users/index.md b/docs/docs/users/index.md
index 21b025d4b..a8f885175 100644
--- a/docs/docs/users/index.md
+++ b/docs/docs/users/index.md
@@ -57,4 +57,3 @@ In this case, the administrator of the instance will need to enable the account.
## Uploading Data
## Sharing Data
-
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 8033d07d8..73f257417 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "clowder-frontend",
- "version": "2.0.0-beta.2",
+ "version": "2.0.0-beta.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/frontend/package.json b/frontend/package.json
index 2681aa035..6f1938575 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "clowder-frontend",
- "version": "2.0.0-beta.2",
+ "version": "2.0.0-beta.3",
"description": "",
"engines": {
"npm": ">=8.11",
diff --git a/frontend/src/app.config.ts b/frontend/src/app.config.ts
index 7c325852c..feeac410e 100644
--- a/frontend/src/app.config.ts
+++ b/frontend/src/app.config.ts
@@ -42,7 +42,7 @@ const hostname =
// TODO when add auth piece remove this env
const apikey = process.env.APIKEY || "";
-config["appVersion"] = "v2.0.0-beta.2";
+config["appVersion"] = "v2.0.0-beta.3";
config["mailingList"] = "clowder@lists.illinois.edu";
config["slackChannel"] =
"https://join.slack.com/t/clowder-software/shared_invite/enQtMzQzOTg0Nzk3OTUzLTYwZDlkZDI0NGI4YmI0ZjE5MTZiYmZhZTIyNWE1YzM0NWMwMzIxODNhZTA1Y2E3MTQzOTg1YThiNzkwOWQwYWE";
diff --git a/frontend/src/openapi/v2/core/OpenAPI.ts b/frontend/src/openapi/v2/core/OpenAPI.ts
index cdf38cb7d..473413160 100644
--- a/frontend/src/openapi/v2/core/OpenAPI.ts
+++ b/frontend/src/openapi/v2/core/OpenAPI.ts
@@ -20,7 +20,7 @@ type Config = {
export const OpenAPI: Config = {
BASE: '',
- VERSION: '2.0.0-beta.2',
+ VERSION: '2.0.0-beta.3',
WITH_CREDENTIALS: false,
CREDENTIALS: 'include',
TOKEN: undefined,
diff --git a/frontend/src/openapi/v2/index.ts b/frontend/src/openapi/v2/index.ts
index 256f73491..24365640b 100644
--- a/frontend/src/openapi/v2/index.ts
+++ b/frontend/src/openapi/v2/index.ts
@@ -5,6 +5,8 @@ export { ApiError } from './core/ApiError';
export { CancelablePromise } from './core/CancelablePromise';
export { OpenAPI } from './core/OpenAPI';
+export type { app__models__groups__Member } from './models/app__models__groups__Member';
+export type { app__models__project__Member } from './models/app__models__project__Member';
export type { AuthorizationBase } from './models/AuthorizationBase';
export type { AuthorizationMetadata } from './models/AuthorizationMetadata';
export type { AuthorizationOut } from './models/AuthorizationOut';
@@ -50,7 +52,6 @@ export type { LicenseIn } from './models/LicenseIn';
export type { LicenseOption } from './models/LicenseOption';
export type { LicenseOut } from './models/LicenseOut';
export type { LocalFileIn } from './models/LocalFileIn';
-export type { Member } from './models/Member';
export type { MetadataAgent } from './models/MetadataAgent';
export type { MetadataConfig } from './models/MetadataConfig';
export type { MetadataDefinitionIn } from './models/MetadataDefinitionIn';
@@ -65,6 +66,8 @@ export type { MetadataRequiredForItems } from './models/MetadataRequiredForItems
export type { MongoDBRef } from './models/MongoDBRef';
export type { Paged } from './models/Paged';
export type { PageMetadata } from './models/PageMetadata';
+export type { ProjectIn } from './models/ProjectIn';
+export type { ProjectOut } from './models/ProjectOut';
export type { Repository } from './models/Repository';
export { RoleType } from './models/RoleType';
export type { SearchCriteria } from './models/SearchCriteria';
@@ -96,6 +99,7 @@ export { LicensesService } from './services/LicensesService';
export { ListenersService } from './services/ListenersService';
export { LoginService } from './services/LoginService';
export { MetadataService } from './services/MetadataService';
+export { ProjectsService } from './services/ProjectsService';
export { PublicDatasetsService } from './services/PublicDatasetsService';
export { PublicElasticsearchService } from './services/PublicElasticsearchService';
export { PublicFilesService } from './services/PublicFilesService';
diff --git a/frontend/src/openapi/v2/models/GroupBase.ts b/frontend/src/openapi/v2/models/GroupBase.ts
index 1c1504b9f..e76425662 100644
--- a/frontend/src/openapi/v2/models/GroupBase.ts
+++ b/frontend/src/openapi/v2/models/GroupBase.ts
@@ -2,10 +2,10 @@
/* tslint:disable */
/* eslint-disable */
-import type { Member } from './Member';
+import type { app__models__groups__Member } from './app__models__groups__Member';
export type GroupBase = {
name: string;
description?: string;
- users?: Array;
+ users?: Array;
}
diff --git a/frontend/src/openapi/v2/models/GroupIn.ts b/frontend/src/openapi/v2/models/GroupIn.ts
index bb97af6d5..5b0ee67ed 100644
--- a/frontend/src/openapi/v2/models/GroupIn.ts
+++ b/frontend/src/openapi/v2/models/GroupIn.ts
@@ -2,10 +2,10 @@
/* tslint:disable */
/* eslint-disable */
-import type { Member } from './Member';
+import type { app__models__groups__Member } from './app__models__groups__Member';
export type GroupIn = {
name: string;
description?: string;
- users?: Array;
+ users?: Array;
}
diff --git a/frontend/src/openapi/v2/models/GroupOut.ts b/frontend/src/openapi/v2/models/GroupOut.ts
index 854b1c078..78fb1f8f4 100644
--- a/frontend/src/openapi/v2/models/GroupOut.ts
+++ b/frontend/src/openapi/v2/models/GroupOut.ts
@@ -2,7 +2,7 @@
/* tslint:disable */
/* eslint-disable */
-import type { Member } from './Member';
+import type { app__models__groups__Member } from './app__models__groups__Member';
/**
* Document Mapping class.
@@ -23,7 +23,7 @@ export type GroupOut = {
modified?: string;
name: string;
description?: string;
- users?: Array;
+ users?: Array;
id?: string;
views?: number;
}
diff --git a/frontend/src/openapi/v2/models/ProjectIn.ts b/frontend/src/openapi/v2/models/ProjectIn.ts
new file mode 100644
index 000000000..2733684f1
--- /dev/null
+++ b/frontend/src/openapi/v2/models/ProjectIn.ts
@@ -0,0 +1,19 @@
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+
+import type { app__models__project__Member } from './app__models__project__Member';
+import type { UserOut } from './UserOut';
+
+export type ProjectIn = {
+ _id?: string;
+ name: string;
+ description?: string;
+ created?: string;
+ modified?: string;
+ dataset_ids?: Array;
+ folder_ids?: Array;
+ file_ids?: Array;
+ creator: UserOut;
+ users?: Array;
+}
diff --git a/frontend/src/openapi/v2/models/ProjectOut.ts b/frontend/src/openapi/v2/models/ProjectOut.ts
new file mode 100644
index 000000000..448f5027f
--- /dev/null
+++ b/frontend/src/openapi/v2/models/ProjectOut.ts
@@ -0,0 +1,32 @@
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+
+import type { app__models__project__Member } from './app__models__project__Member';
+import type { UserOut } from './UserOut';
+
+/**
+ * Document Mapping class.
+ *
+ * Fields:
+ *
+ * - `id` - MongoDB document ObjectID "_id" field.
+ * Mapped to the PydanticObjectId class
+ *
+ * Inherited from:
+ *
+ * - Pydantic BaseModel
+ * - [UpdateMethods](https://roman-right.github.io/beanie/api/interfaces/#aggregatemethods)
+ */
+export type ProjectOut = {
+ id?: string;
+ name: string;
+ description?: string;
+ created?: string;
+ modified?: string;
+ dataset_ids?: Array;
+ folder_ids?: Array;
+ file_ids?: Array;
+ creator: UserOut;
+ users?: Array;
+}
diff --git a/frontend/src/openapi/v2/models/Member.ts b/frontend/src/openapi/v2/models/app__models__groups__Member.ts
similarity index 78%
rename from frontend/src/openapi/v2/models/Member.ts
rename to frontend/src/openapi/v2/models/app__models__groups__Member.ts
index 9d67800af..6eef8cf15 100644
--- a/frontend/src/openapi/v2/models/Member.ts
+++ b/frontend/src/openapi/v2/models/app__models__groups__Member.ts
@@ -4,7 +4,7 @@
import type { UserOut } from './UserOut';
-export type Member = {
+export type app__models__groups__Member = {
user: UserOut;
editor?: boolean;
}
diff --git a/frontend/src/openapi/v2/models/app__models__project__Member.ts b/frontend/src/openapi/v2/models/app__models__project__Member.ts
new file mode 100644
index 000000000..2167310de
--- /dev/null
+++ b/frontend/src/openapi/v2/models/app__models__project__Member.ts
@@ -0,0 +1,10 @@
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+
+import type { UserOut } from './UserOut';
+
+export type app__models__project__Member = {
+ user: UserOut;
+ editor?: boolean;
+}
diff --git a/frontend/src/openapi/v2/services/ProjectsService.ts b/frontend/src/openapi/v2/services/ProjectsService.ts
new file mode 100644
index 000000000..47607f3c0
--- /dev/null
+++ b/frontend/src/openapi/v2/services/ProjectsService.ts
@@ -0,0 +1,265 @@
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+import type { Paged } from '../models/Paged';
+import type { ProjectIn } from '../models/ProjectIn';
+import type { ProjectOut } from '../models/ProjectOut';
+import type { CancelablePromise } from '../core/CancelablePromise';
+import { request as __request } from '../core/request';
+
+export class ProjectsService {
+
+ /**
+ * Get Projects
+ * @param skip
+ * @param limit
+ * @param mine
+ * @param enableAdmin
+ * @returns Paged Successful Response
+ * @throws ApiError
+ */
+ public static getProjectsApiV2ProjectsGet(
+ skip?: number,
+ limit: number = 10,
+ mine: boolean = false,
+ enableAdmin: boolean = false,
+ ): CancelablePromise {
+ return __request({
+ method: 'GET',
+ path: `/api/v2/projects`,
+ query: {
+ 'skip': skip,
+ 'limit': limit,
+ 'mine': mine,
+ 'enable_admin': enableAdmin,
+ },
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Save Project
+ * @param requestBody
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static saveProjectApiV2ProjectsPost(
+ requestBody: ProjectIn,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects`,
+ body: requestBody,
+ mediaType: 'application/json',
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Add Dataset
+ * @param projectId
+ * @param datasetId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static addDatasetApiV2ProjectsProjectIdAddDatasetDatasetIdPost(
+ projectId: string,
+ datasetId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/add_dataset/${datasetId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Remove Dataset
+ * @param projectId
+ * @param datasetId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static removeDatasetApiV2ProjectsProjectIdRemoveDatasetDatasetIdPost(
+ projectId: string,
+ datasetId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/remove_dataset/${datasetId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Add Folder
+ * @param projectId
+ * @param folderId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static addFolderApiV2ProjectsProjectIdAddFolderFolderIdPost(
+ projectId: string,
+ folderId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/add_folder/${folderId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Remove Folder
+ * @param projectId
+ * @param folderId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static removeFolderApiV2ProjectsProjectIdRemoveFolderFolderIdPost(
+ projectId: string,
+ folderId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/remove_folder/${folderId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Add File
+ * @param projectId
+ * @param fileId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static addFileApiV2ProjectsProjectIdAddFileFileIdPost(
+ projectId: string,
+ fileId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/add_file/${fileId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Remove File
+ * @param projectId
+ * @param fileId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static removeFileApiV2ProjectsProjectIdRemoveFileFileIdPost(
+ projectId: string,
+ fileId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/remove_file/${fileId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Get Project
+ * @param projectId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static getProjectApiV2ProjectsProjectIdGet(
+ projectId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'GET',
+ path: `/api/v2/projects/${projectId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Delete Project
+ * @param projectId
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static deleteProjectApiV2ProjectsProjectIdDelete(
+ projectId: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'DELETE',
+ path: `/api/v2/projects/${projectId}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Add Member
+ * Add a new user to a group.
+ * @param projectId
+ * @param username
+ * @param role
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static addMemberApiV2ProjectsProjectIdAddMemberUsernamePost(
+ projectId: string,
+ username: string,
+ role?: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/add_member/${username}`,
+ query: {
+ 'role': role,
+ },
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+ /**
+ * Remove Member
+ * Remove a user from a group.
+ * @param projectId
+ * @param username
+ * @returns ProjectOut Successful Response
+ * @throws ApiError
+ */
+ public static removeMemberApiV2ProjectsProjectIdRemoveMemberUsernamePost(
+ projectId: string,
+ username: string,
+ ): CancelablePromise {
+ return __request({
+ method: 'POST',
+ path: `/api/v2/projects/${projectId}/remove_member/${username}`,
+ errors: {
+ 422: `Validation Error`,
+ },
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/openapi.json b/openapi.json
index 74418d8de..783e88904 100644
--- a/openapi.json
+++ b/openapi.json
@@ -11,7 +11,7 @@
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
},
- "version": "2.0.0-beta.2"
+ "version": "2.0.0-beta.3"
},
"paths": {
"/api/v2/users": {
@@ -10919,6 +10919,638 @@
}
}
},
+ "/api/v2/projects": {
+ "get": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Get Projects",
+ "operationId": "get_projects_api_v2_projects_get",
+ "parameters": [
+ {
+ "required": false,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0
+ },
+ "name": "skip",
+ "in": "query"
+ },
+ {
+ "required": false,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 10
+ },
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "required": false,
+ "schema": {
+ "title": "Mine",
+ "type": "boolean",
+ "default": false
+ },
+ "name": "mine",
+ "in": "query"
+ },
+ {
+ "required": false,
+ "schema": {
+ "title": "Enable Admin",
+ "type": "boolean",
+ "default": false
+ },
+ "name": "enable_admin",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Paged"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "OAuth2AuthorizationCodeBearer": []
+ },
+ {
+ "APIKeyHeader": []
+ }
+ ]
+ },
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Save Project",
+ "operationId": "save_project_api_v2_projects_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectIn"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "OAuth2AuthorizationCodeBearer": []
+ },
+ {
+ "APIKeyHeader": []
+ },
+ {
+ "APIKeyCookie": []
+ }
+ ]
+ }
+ },
+ "/api/v2/projects/{project_id}/add_dataset/{dataset_id}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Add Dataset",
+ "operationId": "add_dataset_api_v2_projects__project_id__add_dataset__dataset_id__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "Dataset Id",
+ "type": "string"
+ },
+ "name": "dataset_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/remove_dataset/{dataset_id}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Remove Dataset",
+ "operationId": "remove_dataset_api_v2_projects__project_id__remove_dataset__dataset_id__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "Dataset Id",
+ "type": "string"
+ },
+ "name": "dataset_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/add_folder/{folder_id}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Add Folder",
+ "operationId": "add_folder_api_v2_projects__project_id__add_folder__folder_id__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "Folder Id",
+ "type": "string"
+ },
+ "name": "folder_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/remove_folder/{folder_id}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Remove Folder",
+ "operationId": "remove_folder_api_v2_projects__project_id__remove_folder__folder_id__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "Folder Id",
+ "type": "string"
+ },
+ "name": "folder_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/add_file/{file_id}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Add File",
+ "operationId": "add_file_api_v2_projects__project_id__add_file__file_id__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "File Id",
+ "type": "string"
+ },
+ "name": "file_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/remove_file/{file_id}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Remove File",
+ "operationId": "remove_file_api_v2_projects__project_id__remove_file__file_id__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "File Id",
+ "type": "string"
+ },
+ "name": "file_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}": {
+ "get": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Get Project",
+ "operationId": "get_project_api_v2_projects__project_id__get",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Delete Project",
+ "operationId": "delete_project_api_v2_projects__project_id__delete",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/add_member/{username}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Add Member",
+ "description": "Add a new user to a group.",
+ "operationId": "add_member_api_v2_projects__project_id__add_member__username__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "Username",
+ "type": "string"
+ },
+ "name": "username",
+ "in": "path"
+ },
+ {
+ "required": false,
+ "schema": {
+ "title": "Role",
+ "type": "string"
+ },
+ "name": "role",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v2/projects/{project_id}/remove_member/{username}": {
+ "post": {
+ "tags": [
+ "projects"
+ ],
+ "summary": "Remove Member",
+ "description": "Remove a user from a group.",
+ "operationId": "remove_member_api_v2_projects__project_id__remove_member__username__post",
+ "parameters": [
+ {
+ "required": true,
+ "schema": {
+ "title": "Project Id",
+ "type": "string"
+ },
+ "name": "project_id",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "title": "Username",
+ "type": "string"
+ },
+ "name": "username",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectOut"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v2/licenses": {
"post": {
"tags": [
@@ -12989,7 +13621,7 @@
"title": "Users",
"type": "array",
"items": {
- "$ref": "#/components/schemas/Member"
+ "$ref": "#/components/schemas/app__models__groups__Member"
},
"default": []
}
@@ -13014,7 +13646,7 @@
"title": "Users",
"type": "array",
"items": {
- "$ref": "#/components/schemas/Member"
+ "$ref": "#/components/schemas/app__models__groups__Member"
},
"default": []
}
@@ -13055,7 +13687,7 @@
"title": "Users",
"type": "array",
"items": {
- "$ref": "#/components/schemas/Member"
+ "$ref": "#/components/schemas/app__models__groups__Member"
},
"default": []
},
@@ -13365,23 +13997,6 @@
},
"description": "Used when adding a file from a local disk."
},
- "Member": {
- "title": "Member",
- "required": [
- "user"
- ],
- "type": "object",
- "properties": {
- "user": {
- "$ref": "#/components/schemas/UserOut"
- },
- "editor": {
- "title": "Editor",
- "type": "boolean",
- "default": false
- }
- }
- },
"MetadataAgent": {
"title": "MetadataAgent",
"required": [
@@ -13890,6 +14505,173 @@
}
}
},
+ "ProjectIn": {
+ "title": "ProjectIn",
+ "required": [
+ "name",
+ "creator"
+ ],
+ "type": "object",
+ "properties": {
+ "_id": {
+ "title": " Id",
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "created": {
+ "title": "Created",
+ "type": "string",
+ "format": "date-time"
+ },
+ "modified": {
+ "title": "Modified",
+ "type": "string",
+ "format": "date-time"
+ },
+ "dataset_ids": {
+ "title": "Dataset Ids",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "default": []
+ },
+ "folder_ids": {
+ "title": "Folder Ids",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "default": []
+ },
+ "file_ids": {
+ "title": "File Ids",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "default": []
+ },
+ "creator": {
+ "$ref": "#/components/schemas/UserOut"
+ },
+ "users": {
+ "title": "Users",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/app__models__project__Member"
+ },
+ "default": []
+ }
+ }
+ },
+ "ProjectOut": {
+ "title": "ProjectOut",
+ "required": [
+ "name",
+ "creator"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "title": "Id",
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "created": {
+ "title": "Created",
+ "type": "string",
+ "format": "date-time"
+ },
+ "modified": {
+ "title": "Modified",
+ "type": "string",
+ "format": "date-time"
+ },
+ "dataset_ids": {
+ "title": "Dataset Ids",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "default": []
+ },
+ "folder_ids": {
+ "title": "Folder Ids",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "default": []
+ },
+ "file_ids": {
+ "title": "File Ids",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "examples": [
+ "5eb7cf5a86d9755df3a6c593",
+ "5eb7cfb05e32e07750a1756a"
+ ]
+ },
+ "default": []
+ },
+ "creator": {
+ "$ref": "#/components/schemas/UserOut"
+ },
+ "users": {
+ "title": "Users",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/app__models__project__Member"
+ },
+ "default": []
+ }
+ },
+ "description": "Document Mapping class.\n\nFields:\n\n- `id` - MongoDB document ObjectID \"_id\" field.\nMapped to the PydanticObjectId class\n\nInherited from:\n\n- Pydantic BaseModel\n- [UpdateMethods](https://roman-right.github.io/beanie/api/interfaces/#aggregatemethods)"
+ },
"Repository": {
"title": "Repository",
"type": "object",
@@ -13972,7 +14754,7 @@
"version": {
"title": "Version",
"type": "string",
- "default": "2.0.0-beta.2"
+ "default": "2.0.0-beta.3"
}
}
},
@@ -14423,6 +15205,40 @@
}
},
"description": "Document Mapping class.\n\nFields:\n\n- `id` - MongoDB document ObjectID \"_id\" field.\nMapped to the PydanticObjectId class\n\nInherited from:\n\n- Pydantic BaseModel\n- [UpdateMethods](https://roman-right.github.io/beanie/api/interfaces/#aggregatemethods)"
+ },
+ "app__models__groups__Member": {
+ "title": "Member",
+ "required": [
+ "user"
+ ],
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/UserOut"
+ },
+ "editor": {
+ "title": "Editor",
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "app__models__project__Member": {
+ "title": "Member",
+ "required": [
+ "user"
+ ],
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/UserOut"
+ },
+ "editor": {
+ "title": "Editor",
+ "type": "boolean",
+ "default": false
+ }
+ }
}
},
"securitySchemes": {