diff --git a/README.md b/README.md
index 9e62bb10b..77d1d4f06 100644
--- a/README.md
+++ b/README.md
@@ -13,26 +13,10 @@ you can optionally use volumes to persist state:
```sh
# run container in background and persist data (docs, nginx configs and tokens database as well as the content index)
# use 'ghcr.io/docat-org/docat:unstable' to get the latest changes
-mkdir -p docat-run/db && touch docat-run/db/db.json && touch docat-run/db/index.json
+mkdir -p docat-run/
docker run \
--detach \
- --volume $PWD/docat-run/doc:/var/docat/doc/ \
- --volume $PWD/docat-run/db/:/app/docat/ \
- --publish 8000:80 \
- ghcr.io/docat-org/docat
-```
-
-*Alternative:* Mount a dedicated directory to host `db.json` and `index.json`:
-
-```sh
-# run container in background and persist data (docs, nginx configs and tokens database as well as the content index)
-# use 'ghcr.io/docat-org/docat:unstable' to get the latest changes
-mkdir -p docat-run/db && touch docat-run/db/db.json && touch docat-run/db/index.json
-docker run \
- --detach \
- --volume $PWD/docat-run/doc:/var/docat/doc/ \
- --volume $PWD/docat-run/db:/var/docat/db/ \
- --env DOCAT_DB_DIR=/var/docat/db/
+ --volume $PWD/docat-run/doc:/var/docat/ \
--publish 8000:80 \
ghcr.io/docat-org/docat
```
@@ -53,7 +37,7 @@ DEV_DOC_PATH="$(mktemp -d)"
poetry install
# run the local development version
-DOCAT_SERVE_FILES=1 DOCAT_INDEX_FILES=1 DOCAT_DOC_PATH="$DEV_DOC_PATH" poetry run python -m docat
+DOCAT_SERVE_FILES=1 DOCAT_DOC_PATH="$DEV_DOC_PATH" poetry run python -m docat
```
After this you need to start the frontend (inside the `web/` folder):
@@ -116,13 +100,13 @@ It is possible to configure some things after the fact.
Supported config options:
-* headerHTML
+- headerHTML
## Advanced Usage
### Hide Controls
-If you would like to send link to a specific version of the documentation without the option to change the version, you can do so by clicking on the `Hide Controls` button. This will hide the control buttons and change the link, which can then be copied as usual.
+If you would like to send link to a specific version of the documentation without the option to change the version, you can do so by clicking on the `Hide Controls` button. This will hide the control buttons and change the link, which can then be copied as usual.
### Indexing
diff --git a/docat/README.md b/docat/README.md
index 7222bc1c6..1a220709e 100644
--- a/docat/README.md
+++ b/docat/README.md
@@ -20,7 +20,7 @@ poetry install
* **DOCAT_SERVE_FILES**: Serve static documentation instead of a nginx (for testing)
* **DOCAT_INDEX_FILES**: Index files on start for searching
-* **DOCAT_DOC_PATH**: Upload directory for static files (needs to match nginx config)
+* **DOCAT_STORAGE_PATH**: Upload directory for static files (needs to match nginx config)
* **FLASK_DEBUG**: Start flask in debug mode
## Usage
diff --git a/docat/docat/app.py b/docat/docat/app.py
index e43a2e177..5f6b3f502 100644
--- a/docat/docat/app.py
+++ b/docat/docat/app.py
@@ -11,7 +11,7 @@
import secrets
import shutil
from pathlib import Path
-from typing import Optional, Tuple
+from typing import Optional
import magic
from fastapi import Depends, FastAPI, File, Header, Response, UploadFile, status
@@ -22,8 +22,8 @@
from docat.models import (
ApiResponse,
ClaimResponse,
- ProjectDetailResponse,
- ProjectsResponse,
+ ProjectDetail,
+ Projects,
SearchResponse,
SearchResultFile,
SearchResultProject,
@@ -56,36 +56,23 @@
redoc_url="/api/redoc",
)
-DOCAT_DB_DIR_STR = os.getenv("DOCAT_DB_DIR")
+DOCAT_STORAGE_PATH = Path(os.getenv("DOCAT_STORAGE_PATH") or Path("/var/docat"))
+DOCAT_DB_PATH = DOCAT_STORAGE_PATH / DB_PATH
+DOCAT_INDEX_PATH = DOCAT_STORAGE_PATH / INDEX_PATH
+DOCAT_UPLOAD_FOLDER = DOCAT_STORAGE_PATH / UPLOAD_FOLDER
-if not DOCAT_DB_DIR_STR:
- # Default Database locations
- DOCAT_DB_DIR = Path.cwd()
- DOCAT_DB_PATH = Path(DB_PATH)
- DOCAT_INDEX_PATH = Path(INDEX_PATH)
-else:
- # Custom Database locations
- DOCAT_DB_DIR = Path(DOCAT_DB_DIR_STR)
- DOCAT_DB_PATH = DOCAT_DB_DIR / "db.json"
- DOCAT_INDEX_PATH = DOCAT_DB_DIR / "index.json"
-
-DOCAT_DB_DIR.mkdir(parents=True, exist_ok=True)
-DOCAT_DB_PATH.touch()
-DOCAT_INDEX_PATH.touch()
-
-#: Holds the static base path where the uploaded documentation artifacts are stored
-DOCAT_UPLOAD_FOLDER = Path(os.getenv("DOCAT_DOC_PATH", UPLOAD_FOLDER))
-
-if not DOCAT_DB_PATH.exists():
+@app.on_event("startup")
+def startup_create_folders():
+ # Create the folders if they don't exist
DOCAT_UPLOAD_FOLDER.mkdir(parents=True, exist_ok=True)
-
-db = TinyDB(DOCAT_DB_PATH)
+ DOCAT_DB_PATH.touch()
+ DOCAT_INDEX_PATH.touch()
def get_db():
"""Return the cached TinyDB instance."""
- return db
+ return TinyDB(DOCAT_DB_PATH)
@app.post("/api/index/update", response_model=ApiResponse, status_code=status.HTTP_200_OK)
@@ -95,22 +82,22 @@ def update_index():
return ApiResponse(message="Successfully updated search index")
-@app.get("/api/projects", response_model=ProjectsResponse, status_code=status.HTTP_200_OK)
+@app.get("/api/projects", response_model=Projects, status_code=status.HTTP_200_OK)
def get_projects():
if not DOCAT_UPLOAD_FOLDER.exists():
- return ProjectsResponse(projects=[])
+ return Projects(projects=[])
return get_all_projects(DOCAT_UPLOAD_FOLDER)
@app.get(
"/api/projects/{project}",
- response_model=ProjectDetailResponse,
+ response_model=ProjectDetail,
status_code=status.HTTP_200_OK,
responses={status.HTTP_404_NOT_FOUND: {"model": ApiResponse}},
)
@app.get(
"/api/projects/{project}/",
- response_model=ProjectDetailResponse,
+ response_model=ProjectDetail,
status_code=status.HTTP_200_OK,
responses={status.HTTP_404_NOT_FOUND: {"model": ApiResponse}},
)
@@ -127,14 +114,14 @@ def get_project(project):
@app.get("/api/search/", response_model=SearchResponse, status_code=status.HTTP_200_OK)
def search(query: str):
query = query.lower()
- found_projects: list[SearchResultProject] = list()
- found_versions: list[SearchResultVersion] = list()
- found_files: list[SearchResultFile] = list()
+ found_projects: list[SearchResultProject] = []
+ found_versions: list[SearchResultVersion] = []
+ found_files: list[SearchResultFile] = []
index_db = TinyDB(DOCAT_INDEX_PATH)
project_table = index_db.table("projects")
projects = project_table.all()
- all_versions: list[Tuple] = list()
+ all_versions: list[tuple] = []
# Collect all projects that contain the query
for project in projects:
@@ -271,6 +258,9 @@ def hide_version(
with open(hidden_file, "w") as f:
f.close()
+ update_version_index_for_project(DOCAT_UPLOAD_FOLDER, DOCAT_INDEX_PATH, project)
+ remove_file_index_from_db(DOCAT_INDEX_PATH, project, version)
+
return ApiResponse(message=f"Version {version} is now hidden")
@@ -306,6 +296,9 @@ def show_version(
os.remove(hidden_file)
+ update_version_index_for_project(DOCAT_UPLOAD_FOLDER, DOCAT_INDEX_PATH, project)
+ update_file_index_for_project_version(DOCAT_UPLOAD_FOLDER, DOCAT_INDEX_PATH, project, version)
+
return ApiResponse(message=f"Version {version} is now shown")
@@ -331,7 +324,7 @@ def upload(
if base_path.exists():
token_status = check_token_for_project(db, docat_api_key, project)
if token_status.valid:
- remove_docs(project, version)
+ remove_docs(project, version, DOCAT_UPLOAD_FOLDER)
else:
response.status_code = status.HTTP_401_UNAUTHORIZED
return ApiResponse(message=token_status.reason)
@@ -441,7 +434,7 @@ def rename(project: str, new_project_name: str, response: Response, docat_api_ke
def delete(project: str, version: str, response: Response, docat_api_key: str = Header(None), db: TinyDB = Depends(get_db)):
token_status = check_token_for_project(db, docat_api_key, project)
if token_status.valid:
- message = remove_docs(project, version)
+ message = remove_docs(project, version, DOCAT_UPLOAD_FOLDER)
if message:
response.status_code = status.HTTP_404_NOT_FOUND
return ApiResponse(message=message)
@@ -471,6 +464,7 @@ def check_token_for_project(db, token, project) -> TokenStatus:
# serve_local_docs for local testing without a nginx
if os.environ.get("DOCAT_SERVE_FILES"):
+ DOCAT_UPLOAD_FOLDER.mkdir(parents=True, exist_ok=True)
app.mount("/doc", StaticFiles(directory=DOCAT_UPLOAD_FOLDER, html=True), name="docs")
# index local files on start
diff --git a/docat/docat/models.py b/docat/docat/models.py
index 0dd903b6f..fd3cd9347 100644
--- a/docat/docat/models.py
+++ b/docat/docat/models.py
@@ -1,5 +1,4 @@
from dataclasses import dataclass
-from typing import Optional
from pydantic import BaseModel
@@ -7,7 +6,7 @@
@dataclass(frozen=True)
class TokenStatus:
valid: bool
- reason: Optional[str] = None
+ reason: str | None = None
class ApiResponse(BaseModel):
@@ -18,7 +17,7 @@ class ClaimResponse(ApiResponse):
token: str
-class ProjectsResponse(BaseModel):
+class Projects(BaseModel):
projects: list[str]
@@ -27,7 +26,7 @@ class ProjectVersion(BaseModel):
tags: list[str]
-class ProjectDetailResponse(BaseModel):
+class ProjectDetail(BaseModel):
name: str
versions: list[ProjectVersion]
diff --git a/docat/docat/utils.py b/docat/docat/utils.py
index 31100b06d..9c2cd0145 100644
--- a/docat/docat/utils.py
+++ b/docat/docat/utils.py
@@ -11,10 +11,10 @@
from bs4.element import Comment
from tinydb import Query, TinyDB
-from docat.models import ProjectDetailResponse, ProjectsResponse, ProjectVersion
+from docat.models import ProjectDetail, Projects, ProjectVersion
NGINX_CONFIG_PATH = Path("/etc/nginx/locations.d")
-UPLOAD_FOLDER = Path("/var/docat/doc")
+UPLOAD_FOLDER = "doc"
DB_PATH = "db.json"
INDEX_PATH = "index.json"
@@ -55,7 +55,7 @@ def extract_archive(target_file, destination):
target_file.unlink() # remove the zip file
-def remove_docs(project, version):
+def remove_docs(project: str, version: str, upload_folder_path: Path):
"""
Delete documentation
@@ -63,7 +63,7 @@ def remove_docs(project, version):
project (str): name of the project
version (str): project version
"""
- docs = UPLOAD_FOLDER / project / version
+ docs = upload_folder_path / project / version
if docs.exists():
# remove the requested version
# rmtree can not remove a symlink
@@ -99,7 +99,7 @@ def calculate_token(password, salt):
return hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, 100000).hex()
-def get_all_projects(upload_folder_path: Path):
+def get_all_projects(upload_folder_path: Path) -> Projects:
"""
Returns all projects in the upload folder.
"""
@@ -110,7 +110,7 @@ def has_not_hidden_versions(project):
(path / version).is_dir() and not (path / version / ".hidden").exists() for version in (upload_folder_path / project).iterdir()
)
- return ProjectsResponse(
+ return Projects(
projects=list(
filter(
has_not_hidden_versions,
@@ -120,7 +120,7 @@ def has_not_hidden_versions(project):
)
-def get_project_details(upload_folder_path: Path, project_name: str):
+def get_project_details(upload_folder_path: Path, project_name: str) -> ProjectDetail | None:
"""
Returns all versions and tags for a project.
"""
@@ -131,7 +131,7 @@ def get_project_details(upload_folder_path: Path, project_name: str):
tags = [x for x in docs_folder.iterdir() if x.is_dir() and x.is_symlink()]
- return ProjectDetailResponse(
+ return ProjectDetail(
name=project_name,
versions=sorted(
[
@@ -157,8 +157,7 @@ def index_all_projects(
and save it into index.json.
"""
# drop existing index
- if index_db_path.exists():
- open(index_db_path, "w").close()
+ index_db_path.unlink(missing_ok=True)
all_projects = get_all_projects(upload_folder_path).projects
@@ -177,6 +176,9 @@ def update_file_index_for_project(upload_folder_path: Path, index_db_path: Path,
project_details = get_project_details(upload_folder_path, project)
+ if not project_details:
+ return
+
for version in project_details.versions:
update_file_index_for_project_version(upload_folder_path, index_db_path, project, version.name)
@@ -198,7 +200,7 @@ def update_file_index_for_project_version(upload_folder_path: Path, index_db_pat
# save the file path
path = str(file.relative_to(docs_folder))
- content = get_html_content_as_str(file) if file.name.endswith(".html") else ""
+ content = get_html_content(file) if file.name.endswith(".html") else ""
insert_file_index_into_db(index_db_path, project, version, path, content)
@@ -215,11 +217,14 @@ def update_version_index_for_project(upload_folder_path: Path, index_db_path: Pa
details = get_project_details(upload_folder_path, project)
+ if not details:
+ return
+
for version in details.versions:
insert_version_into_version_index(index_db_path, project, version.name, version.tags)
-def get_html_content_as_str(file_path: Path):
+def get_html_content(file_path: Path) -> str:
"""
Returns the content of a html file as a string.
"""
@@ -230,12 +235,11 @@ def html_tag_visible(element):
return True
- with open(file_path, "r") as f:
- file_content = f.read()
- soup = BeautifulSoup(file_content, "html.parser")
- text_content = filter(html_tag_visible, soup.findAll(string=True))
- content = " ".join(t.strip() for t in text_content).lower()
- return content
+ file_content = file_path.read_text()
+ soup = BeautifulSoup(file_content, "html.parser")
+ text_content = filter(html_tag_visible, soup.findAll(string=True))
+ content = " ".join(t.strip() for t in text_content).lower()
+ return content
def insert_file_index_into_db(index_db_path: Path, project: str, version: str, file_path: str, content: str):
@@ -301,12 +305,12 @@ def remove_version_from_version_index(index_db_path: Path, project: str, version
projects_table = index_db.table("projects")
Project = Query()
- found_project = projects_table.search(Project.name == project)[0]
+ found_projects = projects_table.search(Project.name == project)
- if not found_project:
+ if not found_projects:
return
- found_versions = found_project.get("versions")
+ found_versions = found_projects[0].get("versions")
if not found_versions or version not in (v["name"] for v in found_versions):
return
diff --git a/docat/file.txt b/docat/file.txt
deleted file mode 100644
index e69de29bb..000000000
diff --git a/docat/tests/conftest.py b/docat/tests/conftest.py
index 42c3bbf13..d3c946c3e 100644
--- a/docat/tests/conftest.py
+++ b/docat/tests/conftest.py
@@ -4,28 +4,37 @@
import pytest
from fastapi.testclient import TestClient
from tinydb import TinyDB
-from tinydb.storages import MemoryStorage
import docat.app as docat
from docat.utils import create_symlink
-@pytest.fixture
-def client():
+@pytest.fixture(autouse=True)
+def setup_docat_paths():
+ """
+ Set up the temporary paths for the docat app.
+ """
+
temp_dir = tempfile.TemporaryDirectory()
- docat.DOCAT_UPLOAD_FOLDER = Path(temp_dir.name)
+ docat.DOCAT_STORAGE_PATH = Path(temp_dir.name)
+ docat.DOCAT_DB_PATH = Path(temp_dir.name) / "db.json"
docat.DOCAT_INDEX_PATH = Path(temp_dir.name) / "index.json"
- docat.db = TinyDB(storage=MemoryStorage)
- docat.index_db = TinyDB(storage=MemoryStorage)
- yield TestClient(docat.app)
- docat.app.db = None
- docat.app.index_db = None
+ docat.DOCAT_UPLOAD_FOLDER = Path(temp_dir.name) / "doc"
+
+ yield
+
temp_dir.cleanup()
@pytest.fixture
-def upload_folder_path():
- return docat.DOCAT_UPLOAD_FOLDER
+def client():
+ docat.db = TinyDB(docat.DOCAT_DB_PATH)
+ docat.index_db = TinyDB(docat.DOCAT_INDEX_PATH)
+
+ yield TestClient(docat.app)
+
+ docat.app.db = None
+ docat.app.index_db = None
@pytest.fixture
@@ -37,31 +46,22 @@ def client_with_claimed_project(client):
@pytest.fixture
-def temp_project_version(tmp_path):
- docs = tmp_path / "doc"
-
- docs.mkdir()
-
+def temp_project_version():
def __create(project, version):
- version_docs = docs / project / version
+ version_docs = docat.DOCAT_UPLOAD_FOLDER / project / version
version_docs.mkdir(parents=True)
(version_docs / "index.html").touch()
- create_symlink(version_docs, docs / project / "latest")
+ create_symlink(version_docs, docat.DOCAT_UPLOAD_FOLDER / project / "latest")
- return docs
+ return docat.DOCAT_UPLOAD_FOLDER
yield __create
@pytest.fixture
-def index_db_path(upload_folder_path):
- return upload_folder_path / "index.json"
-
-
-@pytest.fixture
-def index_db_project_table(index_db_path):
- index_db = TinyDB(index_db_path)
+def index_db_project_table():
+ index_db = TinyDB(docat.DOCAT_INDEX_PATH)
projects_table = index_db.table("projects")
yield projects_table
@@ -70,8 +70,8 @@ def index_db_project_table(index_db_path):
@pytest.fixture
-def index_db_files_table(index_db_path):
- index_db = TinyDB(index_db_path)
+def index_db_files_table():
+ index_db = TinyDB(docat.DOCAT_INDEX_PATH)
projects_table = index_db.table("files")
yield projects_table
diff --git a/docat/tests/test_hide_show.py b/docat/tests/test_hide_show.py
index c8fcb04ea..e92ebfc2a 100644
--- a/docat/tests/test_hide_show.py
+++ b/docat/tests/test_hide_show.py
@@ -1,7 +1,8 @@
import io
-from pathlib import Path
from unittest.mock import patch
+import docat.app as docat
+
def test_hide(client_with_claimed_project):
"""
@@ -70,11 +71,11 @@ def test_hide_only_version_not_listed_in_projects(client_with_claimed_project):
assert project_details_response.json() == {"name": "some-project", "versions": []}
-def test_hide_creates_hidden_file(client_with_claimed_project, upload_folder_path):
+def test_hide_creates_hidden_file(client_with_claimed_project):
"""
Tests that the hidden file is created when hiding a version
"""
- hidden_file_path = Path(upload_folder_path) / "some-project" / "1.0.0" / ".hidden"
+ hidden_file_path = docat.DOCAT_UPLOAD_FOLDER / "some-project" / "1.0.0" / ".hidden"
# create a version
create_response = client_with_claimed_project.post(
@@ -223,11 +224,11 @@ def test_show(client_with_claimed_project):
}
-def test_show_deletes_hidden_file(client_with_claimed_project, upload_folder_path):
+def test_show_deletes_hidden_file(client_with_claimed_project):
"""
Tests that the hidden file is deleted when requesting show.
"""
- hidden_file_path = Path(upload_folder_path) / "some-project" / "1.0.0" / ".hidden"
+ hidden_file_path = docat.DOCAT_UPLOAD_FOLDER / "some-project" / "1.0.0" / ".hidden"
# create a version
create_response = client_with_claimed_project.post(
diff --git a/docat/tests/test_index.py b/docat/tests/test_index.py
index a38d26299..a61d2984f 100644
--- a/docat/tests/test_index.py
+++ b/docat/tests/test_index.py
@@ -1,9 +1,9 @@
import io
import os
import shutil
-from pathlib import Path
from unittest.mock import patch
+import docat.app as docat
from docat.utils import (
index_all_projects,
insert_file_index_into_db,
@@ -16,7 +16,7 @@
)
-def test_insert_file_index_into_db(client_with_claimed_project, index_db_path, index_db_files_table):
+def test_insert_file_index_into_db(client_with_claimed_project, index_db_files_table):
"""
Tests wether insert_file_index_into_db inserts the correct json into the database.
@@ -25,12 +25,12 @@ def test_insert_file_index_into_db(client_with_claimed_project, index_db_path, i
project = "some-project"
version = "1.0.0"
- insert_file_index_into_db(index_db_path, project, version, "index.html", "hello world")
+ insert_file_index_into_db(docat.DOCAT_INDEX_PATH, project, version, "index.html", "hello world")
assert index_db_files_table.all() == [{"path": "index.html", "content": "hello world", "project": project, "version": version}]
-def test_remove_file_index_from_db(client_with_claimed_project, index_db_path, index_db_files_table):
+def test_remove_file_index_from_db(client_with_claimed_project, index_db_files_table):
"""
Tests wether remove_file_index_from_db removes exactly the json insert_file_index_into_db wrote into the database.
@@ -39,13 +39,13 @@ def test_remove_file_index_from_db(client_with_claimed_project, index_db_path, i
project = "some-project"
version = "1.0.0"
- insert_file_index_into_db(index_db_path, project, version, "index.html", "hello world")
- remove_file_index_from_db(index_db_path, project, version)
+ insert_file_index_into_db(docat.DOCAT_INDEX_PATH, project, version, "index.html", "hello world")
+ remove_file_index_from_db(docat.DOCAT_INDEX_PATH, project, version)
assert index_db_files_table.all() == []
-def test_insert_version_into_version_index(client_with_claimed_project, index_db_path, index_db_project_table):
+def test_insert_version_into_version_index(client_with_claimed_project, index_db_project_table):
"""
Tests wether insert_version_into_version_index inserts the correct json into the database.
@@ -55,12 +55,12 @@ def test_insert_version_into_version_index(client_with_claimed_project, index_db
version = "1.0.0"
tag = "latest"
- insert_version_into_version_index(index_db_path, project, version, [tag])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [tag])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": version, "tags": [tag]}]}]
-def test_insert_version_into_version_index_no_duplicates(client_with_claimed_project, index_db_path, index_db_project_table):
+def test_insert_version_into_version_index_no_duplicates(client_with_claimed_project, index_db_project_table):
"""
Tests wether insert_version_into_version_index doesn't create a new project
or version when the version with the same tags already exists.
@@ -71,13 +71,13 @@ def test_insert_version_into_version_index_no_duplicates(client_with_claimed_pro
version = "1.0.0"
tag = "latest"
- insert_version_into_version_index(index_db_path, project, version, [tag])
- insert_version_into_version_index(index_db_path, project, version, [tag])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [tag])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [tag])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": version, "tags": [tag]}]}]
-def test_insert_version_into_version_index_second(client_with_claimed_project, index_db_path, index_db_project_table):
+def test_insert_version_into_version_index_second(client_with_claimed_project, index_db_project_table):
"""
Tests wether insert_version_into_version_index appends the version when the project already exists.
@@ -89,14 +89,14 @@ def test_insert_version_into_version_index_second(client_with_claimed_project, i
tags = ["latest", "stable"]
for version, tag in zip(versions, tags):
- insert_version_into_version_index(index_db_path, project, version, [tag])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [tag])
assert index_db_project_table.all() == [
{"name": project, "versions": [{"name": versions[0], "tags": [tags[0]]}, {"name": versions[1], "tags": [tags[1]]}]}
]
-def test_insert_version_into_version_index_second_with_different_tags(client_with_claimed_project, index_db_path, index_db_project_table):
+def test_insert_version_into_version_index_second_with_different_tags(client_with_claimed_project, index_db_project_table):
"""
Tests wether insert_version_into_version_index correctly overwrites tags.
For example, when a version is tagged as "latest" and then as "stable" and "nightly" , the "latest" tag should be removed.
@@ -108,16 +108,16 @@ def test_insert_version_into_version_index_second_with_different_tags(client_wit
old_tags = ["latest"]
new_tags = ["stale", "nightly"]
- insert_version_into_version_index(index_db_path, project, version, [old_tags])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [old_tags])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": version, "tags": [old_tags]}]}]
- insert_version_into_version_index(index_db_path, project, version, [new_tags])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [new_tags])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": version, "tags": [new_tags]}]}]
-def test_insert_version_into_version_index_second_with_overlapping_tags(client_with_claimed_project, index_db_path, index_db_project_table):
+def test_insert_version_into_version_index_second_with_overlapping_tags(client_with_claimed_project, index_db_project_table):
"""
Tests wether insert_version_into_version_index correctly overwrites tags.
For example, when a version is tagged as "latest" and then as "stable" and "latest", the tags should become "stable" and "latest".
@@ -129,14 +129,14 @@ def test_insert_version_into_version_index_second_with_overlapping_tags(client_w
old_tags = ["latest"]
new_tags = ["stable", "latest"]
- insert_version_into_version_index(index_db_path, project, version, [old_tags])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [old_tags])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": version, "tags": [old_tags]}]}]
- insert_version_into_version_index(index_db_path, project, version, [new_tags])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [new_tags])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": version, "tags": [new_tags]}]}]
-def test_remove_version_from_version_index(client_with_claimed_project, index_db_path, index_db_project_table):
+def test_remove_version_from_version_index(client_with_claimed_project, index_db_project_table):
"""
Tests that only the version given is removed from the database.
@@ -147,19 +147,17 @@ def test_remove_version_from_version_index(client_with_claimed_project, index_db
tags = ["latest", "stable"]
for version, tag in zip(versions, tags):
- insert_version_into_version_index(index_db_path, project, version, [tag])
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [tag])
assert index_db_project_table.all() == [
{"name": project, "versions": [{"name": versions[0], "tags": [tags[0]]}, {"name": versions[1], "tags": [tags[1]]}]}
]
- remove_version_from_version_index(index_db_path, project, versions[1])
+ remove_version_from_version_index(docat.DOCAT_INDEX_PATH, project, versions[1])
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": versions[0], "tags": [tags[0]]}]}]
-def test_remove_version_from_version_index_remove_last_version(
- client_with_claimed_project, upload_folder_path, index_db_path, index_db_project_table
-):
+def test_remove_version_from_version_index_remove_last_version(client_with_claimed_project, index_db_project_table):
"""
Tests wether remove_version_from_version_index removes the whole project from the database if the last version is removed.
@@ -169,13 +167,13 @@ def test_remove_version_from_version_index_remove_last_version(
version = "1.0.0"
tag = "latest"
- insert_version_into_version_index(index_db_path, project, version, [tag])
- remove_version_from_version_index(index_db_path, project, version)
+ insert_version_into_version_index(docat.DOCAT_INDEX_PATH, project, version, [tag])
+ remove_version_from_version_index(docat.DOCAT_INDEX_PATH, project, version)
assert index_db_project_table.all() == []
-def test_update_version_index_for_project(client_with_claimed_project, upload_folder_path, index_db_path, index_db_project_table):
+def test_update_version_index_for_project(client_with_claimed_project, index_db_project_table):
"""
Tests wether update_version_index_for_project correctly handles inserting and deleting versions.
@@ -184,27 +182,27 @@ def test_update_version_index_for_project(client_with_claimed_project, upload_fo
project = "some-project"
versions = ["1.0.0", "2.0.0"]
- upload_folder = Path(upload_folder_path)
+ project_folder = docat.DOCAT_UPLOAD_FOLDER / project
# we need to create the project folders manually,
# since the api already updates the index
for version in versions:
- (upload_folder / project / version).mkdir(parents=True)
+ (project_folder / version).mkdir(parents=True)
- with open(upload_folder / project / version / "index.html", "w") as f:
+ with open(project_folder / version / "index.html", "w") as f:
f.write("
Hello World
")
- update_version_index_for_project(upload_folder_path, index_db_path, project)
+ update_version_index_for_project(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project)
assert index_db_project_table.all() == [
{"name": project, "versions": [{"name": versions[1], "tags": []}, {"name": versions[0], "tags": []}]}
]
- shutil.rmtree(upload_folder / project / versions[0])
- update_version_index_for_project(upload_folder_path, index_db_path, project)
+ shutil.rmtree(project_folder / versions[0])
+ update_version_index_for_project(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project)
assert index_db_project_table.all() == [{"name": project, "versions": [{"name": versions[1], "tags": []}]}]
-def test_update_file_index_for_project_version(client_with_claimed_project, upload_folder_path, index_db_path, index_db_files_table):
+def test_update_file_index_for_project_version(client_with_claimed_project, index_db_files_table):
"""
Tests wether update_file_index_for_project_version correctly handles inserting and deleting files.
@@ -214,30 +212,28 @@ def test_update_file_index_for_project_version(client_with_claimed_project, uplo
version = "1.0.0"
files = ["index.html", "style.css"]
- upload_folder = Path(upload_folder_path)
-
# we need to create the project folders manually,
# since the api already updates the index
- (upload_folder / project / version).mkdir(parents=True)
+ (docat.DOCAT_UPLOAD_FOLDER / project / version).mkdir(parents=True)
for file in files:
- with open(upload_folder / project / version / file, "w") as f:
+ with open(docat.DOCAT_UPLOAD_FOLDER / project / version / file, "w") as f:
f.write("Hello World
")
- update_file_index_for_project_version(upload_folder_path, index_db_path, project, version)
+ update_file_index_for_project_version(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project, version)
assert index_db_files_table.all().sort(key=lambda e: e.get("path")) == [
{"path": files[1], "content": "", "project": project, "version": version},
{"path": files[0], "content": "hello world", "project": project, "version": version},
].sort(key=lambda e: e["path"])
- os.remove(upload_folder / project / version / files[0])
- update_file_index_for_project_version(upload_folder_path, index_db_path, project, version)
+ os.remove(docat.DOCAT_UPLOAD_FOLDER / project / version / files[0])
+ update_file_index_for_project_version(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project, version)
assert index_db_files_table.all() == [
{"path": files[1], "content": "", "project": project, "version": version},
]
-def test_update_file_index_for_project_version_folder_does_not_exist(client_with_claimed_project, upload_folder_path, index_db_path):
+def test_update_file_index_for_project_version_folder_does_not_exist(client_with_claimed_project):
"""
Tests wether the function just returns when the folder for
the given project / version does not exist.
@@ -246,11 +242,11 @@ def test_update_file_index_for_project_version_folder_does_not_exist(client_with
project = "non-existing-project"
with patch("docat.utils.TinyDB") as mock_tinydb:
- update_file_index_for_project_version(upload_folder_path, index_db_path, project, "1.0.0")
+ update_file_index_for_project_version(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project, "1.0.0")
mock_tinydb.assert_not_called()
-def test_update_file_index_for_project(client_with_claimed_project, upload_folder_path, index_db_path, index_db_files_table):
+def test_update_file_index_for_project(client_with_claimed_project, index_db_files_table):
"""
Tests wether update_file_index_for_project correctly handles inserting and deleting versions.
@@ -259,28 +255,26 @@ def test_update_file_index_for_project(client_with_claimed_project, upload_folde
project = "some-project"
versions = ["1.0.0", "2.0.0"]
- upload_folder = Path(upload_folder_path)
-
# we need to create the project folders manually,
# since the api already updates the index
for version in versions:
- (upload_folder / project / version).mkdir(parents=True)
+ (docat.DOCAT_UPLOAD_FOLDER / project / version).mkdir(parents=True)
- with open(upload_folder / project / version / "index.html", "w") as f:
+ with open(docat.DOCAT_UPLOAD_FOLDER / project / version / "index.html", "w") as f:
f.write("Hello World
")
- update_file_index_for_project(upload_folder_path, index_db_path, project)
+ update_file_index_for_project(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project)
assert index_db_files_table.all().sort(key=lambda e: e.get("version")) == [
{"path": "index.html", "content": "hello world", "project": project, "version": versions[1]},
{"path": "index.html", "content": "hello world", "project": project, "version": versions[0]},
].sort(key=lambda e: e["version"])
- shutil.rmtree(upload_folder / project / versions[0])
- update_file_index_for_project(upload_folder_path, index_db_path, project)
+ shutil.rmtree(docat.DOCAT_UPLOAD_FOLDER / project / versions[0])
+ update_file_index_for_project(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project)
assert index_db_files_table.all() == [{"path": "index.html", "content": "hello world", "project": project, "version": versions[1]}]
-def test_index_project_with_html_content(client_with_claimed_project, upload_folder_path, index_db_path):
+def test_index_project_with_html_content(client_with_claimed_project):
"""
Tests wether the function creates an index for a given project as expected.
"""
@@ -297,10 +291,10 @@ def test_index_project_with_html_content(client_with_claimed_project, upload_fol
assert create_project_response.status_code == 201
with patch("docat.utils.insert_file_index_into_db") as mock_insert_file_index_into_db:
- update_file_index_for_project_version(upload_folder_path, index_db_path, project, version)
+ update_file_index_for_project_version(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project, version)
mock_insert_file_index_into_db.assert_called_once_with(
- index_db_path,
+ docat.DOCAT_INDEX_PATH,
project,
version,
file,
@@ -308,7 +302,7 @@ def test_index_project_with_html_content(client_with_claimed_project, upload_fol
)
-def test_index_project_non_html(client_with_claimed_project, upload_folder_path, index_db_path):
+def test_index_project_non_html(client_with_claimed_project):
"""
Tests wether the function ignores the content of non-html files as expected.
"""
@@ -325,9 +319,9 @@ def test_index_project_non_html(client_with_claimed_project, upload_folder_path,
assert create_project_response.status_code == 201
with patch("docat.utils.insert_file_index_into_db") as mock_insert_file_index_into_db:
- update_file_index_for_project_version(upload_folder_path, index_db_path, project, version)
+ update_file_index_for_project_version(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH, project, version)
mock_insert_file_index_into_db.assert_called_once_with(
- index_db_path,
+ docat.DOCAT_INDEX_PATH,
project,
version,
file,
@@ -335,7 +329,7 @@ def test_index_project_non_html(client_with_claimed_project, upload_folder_path,
)
-def test_index_all_projects_creates_version_and_tag_index(client_with_claimed_project, upload_folder_path, index_db_path):
+def test_index_all_projects_creates_version_and_tag_index(client_with_claimed_project):
"""
Tests wether index_all_projects finds all versions and creates the index accordingly.
"""
@@ -357,12 +351,12 @@ def test_index_all_projects_creates_version_and_tag_index(client_with_claimed_pr
assert tag_project_response.status_code == 201
with patch("docat.utils.insert_version_into_version_index") as mock_insert_version_into_version_index:
- index_all_projects(upload_folder_path, index_db_path)
- mock_insert_version_into_version_index.assert_any_call(index_db_path, project, versions[0], [tags[0]])
- mock_insert_version_into_version_index.assert_any_call(index_db_path, project, versions[1], [tags[1]])
+ index_all_projects(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH)
+ mock_insert_version_into_version_index.assert_any_call(docat.DOCAT_INDEX_PATH, project, versions[0], [tags[0]])
+ mock_insert_version_into_version_index.assert_any_call(docat.DOCAT_INDEX_PATH, project, versions[1], [tags[1]])
-def test_index_all_projects_creates_file_and_version_index(client_with_claimed_project, upload_folder_path, index_db_path):
+def test_index_all_projects_creates_file_and_version_index(client_with_claimed_project):
"""
Tests wether index_all_projects finds all projects and versions and creates the index accordingly.
"""
@@ -381,14 +375,14 @@ def test_index_all_projects_creates_file_and_version_index(client_with_claimed_p
with patch("docat.utils.insert_version_into_version_index") as mock_insert_version_into_version_index, patch(
"docat.utils.insert_file_index_into_db"
) as mock_insert_file_index_into_db:
- index_all_projects(upload_folder_path, index_db_path)
+ index_all_projects(docat.DOCAT_UPLOAD_FOLDER, docat.DOCAT_INDEX_PATH)
for project in projects:
for version in versions:
- mock_insert_version_into_version_index.assert_any_call(index_db_path, project, version, [])
- mock_insert_file_index_into_db.assert_any_call(index_db_path, project, version, "index.html", "hello world")
+ mock_insert_version_into_version_index.assert_any_call(docat.DOCAT_INDEX_PATH, project, version, [])
+ mock_insert_file_index_into_db.assert_any_call(docat.DOCAT_INDEX_PATH, project, version, "index.html", "hello world")
-def test_index_all_projects_creates_file_and_version_index_api(client_with_claimed_project, index_db_path):
+def test_index_all_projects_creates_file_and_version_index_api(client_with_claimed_project):
"""
Tests via the API wether index_all_projects finds all projects and versions and creates the index accordingly.
"""
@@ -412,5 +406,155 @@ def test_index_all_projects_creates_file_and_version_index_api(client_with_claim
for project in projects:
for version in versions:
- mock_insert_version_into_version_index.assert_any_call(index_db_path, project, version, [])
- mock_insert_file_index_into_db.assert_any_call(index_db_path, project, version, "index.html", "hello world")
+ mock_insert_version_into_version_index.assert_any_call(docat.DOCAT_INDEX_PATH, project, version, [])
+ mock_insert_file_index_into_db.assert_any_call(docat.DOCAT_INDEX_PATH, project, version, "index.html", "hello world")
+
+
+def test_hide_show_removes_file_index_and_adds_again_only_version(client_with_claimed_project, index_db_files_table):
+ """
+ Tests that the hide function removes the files of the version from the index and that
+ show adds it again with only one version.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ # create a project with a version
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ # make sure we have the files in the index
+ assert index_db_files_table.all().sort(key=lambda e: e.get("version")) == [
+ {"path": "index.html", "content": "hello world", "project": project, "version": version},
+ ].sort(key=lambda e: e["version"])
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure the files are gone from the index
+ assert index_db_files_table.all() == []
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/show", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure it's back
+ assert index_db_files_table.all().sort(key=lambda e: e.get("version")) == [
+ {"path": "index.html", "content": "hello world", "project": project, "version": version},
+ ].sort(key=lambda e: e["version"])
+
+
+def test_hide_show_removes_file_index_and_adds_again(client_with_claimed_project, index_db_files_table):
+ """
+ Tests that the hide function removes the files of the version from the index and that
+ show adds it again.
+ """
+ project = "some-project"
+ versions = ["1.0.0", "2.0.0"]
+
+ for version in versions:
+ # create a project with a version
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ # make sure we have the files in the index
+ assert index_db_files_table.all().sort(key=lambda e: e.get("version")) == [
+ {"path": "index.html", "content": "hello world", "project": project, "version": version[0]},
+ {"path": "index.html", "content": "hello world", "project": project, "version": version[1]},
+ ].sort(key=lambda e: e["version"])
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{versions[0]}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure the files are gone from the index
+ assert index_db_files_table.all().sort(key=lambda e: e.get("version")) == [
+ {"path": "index.html", "content": "hello world", "project": project, "version": version[1]},
+ ].sort(key=lambda e: e["version"])
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{versions[0]}/show", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure they're back
+ assert index_db_files_table.all().sort(key=lambda e: e.get("version")) == [
+ {"path": "index.html", "content": "hello world", "project": project, "version": version[0]},
+ {"path": "index.html", "content": "hello world", "project": project, "version": version[1]},
+ ].sort(key=lambda e: e["version"])
+
+
+def test_hide_show_removes_project_index_and_adds_again_on_hide_and_show_of_only_version(
+ client_with_claimed_project, index_db_project_table
+):
+ """
+ Tests that the hide function removes the version and project
+ from the index if the only version gets hidden and that show adds it again.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ # create a project with a version
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ # make sure we have the version in the index
+ assert index_db_project_table.all().sort(key=lambda e: e.get("name")) == [
+ {"name": project, "versions": [version]},
+ ].sort(key=lambda e: e["name"])
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure the version and project is gone from the index
+ assert index_db_project_table.all() == []
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/show", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure it's back
+ assert index_db_project_table.all().sort(key=lambda e: e.get("name")) == [
+ {"name": project, "versions": [version]},
+ ].sort(key=lambda e: e["name"])
+
+
+def test_hide_show_removes_version_from_index(client_with_claimed_project, index_db_project_table):
+ """
+ Tests that the hide function removes the version
+ from the index if it gets hidden and that show adds it again.
+ """
+ project = "some-project"
+ versions = ["1.0.0", "2.0.0"]
+
+ for version in versions:
+ # create a project with a version
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ # make sure we have the version in the index
+ assert index_db_project_table.all().sort(key=lambda e: e.get("name")) == [
+ {"name": project, "versions": [{"name": v, "tags": []} for v in versions]},
+ ].sort(key=lambda e: e["name"])
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{versions[0]}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure the version is gone from the index
+ assert index_db_project_table.all().sort(key=lambda e: e.get("name")) == [
+ {"name": project, "versions": [{"name": versions[1], "tags": []}]},
+ ].sort(key=lambda e: e["name"])
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{versions[0]}/show", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ # make sure it's back
+ assert index_db_project_table.all().sort(key=lambda e: e.get("name")) == [
+ {"name": project, "versions": [{"name": v, "tags": []} for v in versions]},
+ ].sort(key=lambda e: e["name"])
diff --git a/docat/tests/test_search.py b/docat/tests/test_search.py
index dbed11799..811b3a417 100644
--- a/docat/tests/test_search.py
+++ b/docat/tests/test_search.py
@@ -1,7 +1,5 @@
import io
-import docat
-
def test_search_finds_project_by_name(client_with_claimed_project):
"""
@@ -247,11 +245,10 @@ def test_index_updated_on_rename(client_with_claimed_project):
}
-def test_search_updated_on_delete(client_with_claimed_project, upload_folder_path):
+def test_search_updated_on_delete(client_with_claimed_project):
"""
The version and it's files should be removed from the index when deleted
"""
- docat.utils.UPLOAD_FOLDER = upload_folder_path
project = "some-project"
version = "1.0.0"
version_to_delete = "1.0.1"
@@ -300,3 +297,360 @@ def test_search_updated_on_delete(client_with_claimed_project, upload_folder_pat
"versions": [],
"files": [],
}
+
+
+def test_search_finds_files_by_name(client_with_claimed_project):
+ """
+ The search should find files by name.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response = client_with_claimed_project.get("/api/search?query=index")
+ assert search_response.status_code == 200
+ assert search_response.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [{"project": project, "version": version, "path": "index.html"}],
+ }
+
+
+def test_search_finds_files_by_content_html(client_with_claimed_project):
+ """
+ The search should find html files by content.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response = client_with_claimed_project.get("/api/search?query=hello%20world")
+ assert search_response.status_code == 200
+ assert search_response.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [{"project": project, "version": version, "path": "index.html"}],
+ }
+
+
+def test_search_ignores_content_for_non_html_files(client_with_claimed_project):
+ """
+ The search should not find content of non-html files.
+ (Should be impossible anyways because indexing should already ignore the content.)
+ """
+
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.txt", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response = client_with_claimed_project.get("/api/search?query=hello%20world")
+ assert search_response.status_code == 200
+ assert search_response.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+
+def test_search_ignores_files_of_hidden_versions_by_name(client_with_claimed_project):
+ """
+ After a version was hidden, it's files should not be found by name anymore.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.txt", io.BytesIO(b"Lorem ipsum dolor sit..."), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=index")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [{"project": project, "version": version, "path": "index.txt"}],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_2 = client_with_claimed_project.get("/api/search?query=index")
+ assert search_response_2.status_code == 200
+ assert search_response_2.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+
+def test_search_ignores_files_of_hidden_versions_by_content(client_with_claimed_project):
+ """
+ After a version was hidden, it's files should not be found by html content anymore.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=hello%20world")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [{"project": project, "version": version, "path": "index.html"}],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_2 = client_with_claimed_project.get("/api/search?query=hello%20world")
+ assert search_response_2.status_code == 200
+ assert search_response_2.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+
+def test_search_ignores_project_with_only_hidden_versions(client_with_claimed_project):
+ """
+ The project should not be found when all it's versions are hidden.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=some-project")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [{"name": project}],
+ "versions": [],
+ "files": [],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_2 = client_with_claimed_project.get("/api/search?query=some-project")
+ assert search_response_2.status_code == 200
+ assert search_response_2.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+
+def test_search_finds_project_with_only_hidden_versions_after_showing(client_with_claimed_project):
+ """
+ The project should be found again when all it's versions are hidden and then shown again.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=some-project")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [{"name": project}],
+ "versions": [],
+ "files": [],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_2 = client_with_claimed_project.get("/api/search?query=some-project")
+ assert search_response_2.status_code == 200
+ assert search_response_2.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/show", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=some-project")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [{"name": project}],
+ "versions": [],
+ "files": [],
+ }
+
+
+def test_search_ignores_hidden_versions(client_with_claimed_project):
+ """
+ The version should not be found when it's hidden.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=1.0")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [],
+ "versions": [{"project": project, "version": version}],
+ "files": [],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_2 = client_with_claimed_project.get("/api/search?query=1.0.0")
+ assert search_response_2.status_code == 200
+ assert search_response_2.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+
+def test_search_finds_shown_versions_after_hide(client_with_claimed_project):
+ """
+ The version should be found again after it's hidden and shown again.
+ """
+ project = "some-project"
+ version = "1.0.0"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": ("index.html", io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=1.0")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [],
+ "versions": [{"project": project, "version": version}],
+ "files": [],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/hide", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_2 = client_with_claimed_project.get("/api/search?query=1.0")
+ assert search_response_2.status_code == 200
+ assert search_response_2.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [],
+ }
+
+ hide_version_response = client_with_claimed_project.post(f"/api/{project}/{version}/show", headers={"Docat-Api-Key": "1234"})
+ assert hide_version_response.status_code == 200
+
+ search_response_1 = client_with_claimed_project.get("/api/search?query=1.0")
+ assert search_response_1.status_code == 200
+ assert search_response_1.json() == {
+ "projects": [],
+ "versions": [{"project": project, "version": version}],
+ "files": [],
+ }
+
+
+def test_search_project_version_and_file_match(client_with_claimed_project):
+ """
+ Test that the search finds the project, the version and a file with a matching name at the same time.
+ """
+ project = "some-project"
+ version = "some-version"
+ file = "some-file.html"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": (file, io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response = client_with_claimed_project.get("/api/search?query=some")
+ assert search_response.status_code == 200
+ assert search_response.json() == {
+ "projects": [{"name": project}],
+ "versions": [{"project": project, "version": version}],
+ "files": [{"project": project, "version": version, "path": file}],
+ }
+
+
+def test_search_project_version_content_match(client_with_claimed_project):
+ """
+ Test that the search finds the project, the version and the file with matching content at the same time.
+ """
+ project = "some-project"
+ version = "some-version"
+ file = "index.html"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": (file, io.BytesIO(b"some content
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response = client_with_claimed_project.get("/api/search?query=some")
+ assert search_response.status_code == 200
+ assert search_response.json() == {
+ "projects": [{"name": project}],
+ "versions": [{"project": project, "version": version}],
+ "files": [{"project": project, "version": version, "path": file}],
+ }
+
+
+def test_search_file_and_content_match_no_duplicates(client_with_claimed_project):
+ """
+ Test that the search only returns the file once when the file name and the content match.
+ """
+ project = "some-project"
+ version = "1.0.0"
+ file = "hello-world.html"
+
+ create_project_response = client_with_claimed_project.post(
+ f"/api/{project}/{version}",
+ files={"file": (file, io.BytesIO(b"Hello World
"), "plain/text")},
+ )
+ assert create_project_response.status_code == 201
+
+ search_response = client_with_claimed_project.get("/api/search?query=hello")
+ assert search_response.status_code == 200
+ assert search_response.json() == {
+ "projects": [],
+ "versions": [],
+ "files": [{"project": project, "version": version, "path": file}],
+ }
diff --git a/docat/tests/test_setup.py b/docat/tests/test_setup.py
deleted file mode 100644
index 671acc5c6..000000000
--- a/docat/tests/test_setup.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# import io
-# import os
-# import tempfile
-# from pathlib import Path
-# from unittest.mock import patch
-
-# import docat.utils as utils
-
-# def test_creates_missing_db_folder_and_files():
-# temp_dir = tempfile.TemporaryDirectory()
-# db_dir = os.path.join(temp_dir.name, "db")
-# utils.UPLOAD_FOLDER = Path(temp_dir.name)
-
-# with patch("os.makedirs") as makedirs_mock:
-# import docat.app as docat
-
-# docat.update_index()
-
-# assert docat.DOCAT_DB_DIR == db_dir
-# assert docat.DOCAT_DB_PATH == os.path.join(db_dir, "db.json")
-# assert docat.DOCAT_INDEX_PATH == os.path.join(db_dir, "index.json")
-
-# temp_dir.cleanup()
diff --git a/docat/tests/test_upload.py b/docat/tests/test_upload.py
index 86fb200ff..1d5746693 100644
--- a/docat/tests/test_upload.py
+++ b/docat/tests/test_upload.py
@@ -30,7 +30,7 @@ def test_successfully_override(client_with_claimed_project):
assert response.status_code == 201
assert response_data["message"] == "File successfully uploaded"
- assert remove_mock.mock_calls == [call("some-project", "1.0.0")]
+ assert remove_mock.mock_calls == [call("some-project", "1.0.0", docat.DOCAT_UPLOAD_FOLDER)]
def test_tags_are_not_overwritten_without_api_key(client_with_claimed_project):
diff --git a/docat/tests/test_utils.py b/docat/tests/test_utils.py
index 2ae3bd2b1..959ad2e92 100644
--- a/docat/tests/test_utils.py
+++ b/docat/tests/test_utils.py
@@ -1,6 +1,7 @@
from pathlib import Path
from unittest.mock import MagicMock, patch
+import docat.app as docat
from docat.utils import create_symlink, extract_archive, remove_docs
@@ -70,11 +71,10 @@ def test_archive_artifact():
def test_remove_version(temp_project_version):
docs = temp_project_version("project", "1.0")
- with patch("docat.utils.UPLOAD_FOLDER", docs):
- remove_docs("project", "1.0")
+ remove_docs("project", "1.0", docat.DOCAT_UPLOAD_FOLDER)
- assert docs.exists()
- assert not (docs / "project").exists()
+ assert docs.exists()
+ assert not (docs / "project").exists()
def test_remove_symlink_version(temp_project_version):
@@ -83,7 +83,6 @@ def test_remove_symlink_version(temp_project_version):
symlink_to_latest = docs / project / "latest"
assert symlink_to_latest.is_symlink()
- with patch("docat.utils.UPLOAD_FOLDER", docs):
- remove_docs(project, "latest")
+ remove_docs(project, "latest", docat.DOCAT_UPLOAD_FOLDER)
- assert not symlink_to_latest.exists()
+ assert not symlink_to_latest.exists()