Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to react #351

Merged
merged 48 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ee9562e
Migration: Initialize new React project
reglim Oct 24, 2022
48aaad7
Migration: Add Header and Footer
reglim Oct 24, 2022
ea0f878
Migration: Add Home page
reglim Oct 24, 2022
af4377b
Migration: Add Project Overview Page
reglim Oct 25, 2022
01b5b79
Migration: Add Upload, Delete and Claim Button as well as Tooltips
reglim Oct 25, 2022
b5734e1
Migration: Add Favorite functionality
reglim Oct 25, 2022
cf35e64
Migration: Cleanup Project by splitting off components
reglim Oct 26, 2022
b9d1aa5
Migration: Add Upload Page
reglim Oct 26, 2022
a5b6da7
Migration: Fix Links not working sometimes
reglim Oct 26, 2022
8501dc7
Migration: Add Help, Docs and 404 Error Page
reglim Oct 26, 2022
c91b3af
Migration: Refactoring
reglim Nov 8, 2022
041a6c3
Migration: Add Claim Page
reglim Nov 8, 2022
6efe778
Migration: Split style folder in components and pages
reglim Nov 8, 2022
f4f11bf
Migration: Move CSS for Project subhead
reglim Nov 8, 2022
77986a9
Migration: Seperate CSS into Modules
reglim Nov 8, 2022
f3bb814
Migration: Add Delete Page (WIP)
reglim Nov 9, 2022
28f133e
Migration: Split Banner into seperate Component
reglim Nov 9, 2022
3a2c0b5
Migration: Seperte Navigation Link into seperate component
reglim Nov 9, 2022
fa6963d
Migration: Split off DataSelect
reglim Nov 9, 2022
d0e19b9
Migration: Create Style Layout for all Pages
reglim Nov 9, 2022
249bf3b
Migration: Revert fixing the footer at the bottom
reglim Nov 9, 2022
a994dd1
Migration: Add margin to help page at bottom
reglim Nov 14, 2022
89190d5
Migration: Adapt style of Upload page to Material Style
reglim Nov 14, 2022
6a3e87d
Migration: Add Validation to Claim, Upload and Delete Pages
reglim Nov 14, 2022
786f4fd
Migration: Fix Links not replaced on help page
reglim Nov 14, 2022
bb807f0
Migration: Fix Header not read from config
reglim Nov 14, 2022
473c187
Migration: Fix Version priority on docs page and other improvements
reglim Nov 15, 2022
6a2f922
Migration: Fix Add Prop for single control buttons so they're fixed a…
reglim Nov 15, 2022
504b625
Migration: Fix Messages when loading failed
reglim Nov 16, 2022
eaf72cd
Migration: Fix Data Fetching
reglim Nov 21, 2022
f9ca626
Migration: Fix Validation Messages moving content
reglim Nov 22, 2022
1d2a455
Migration: Add Linting and ReadMe
reglim Nov 23, 2022
5dfd39b
Migration: Implement Linting Suggestions
reglim Nov 23, 2022
7138e84
Migration: Fix Data Fetching
reglim Nov 28, 2022
8db401b
Migration: Add Reload function to ProjectDataProvider
reglim Nov 28, 2022
72b19db
Migration: Fix Data Fetching
reglim Nov 28, 2022
6e04b0f
Migration: Switch to HashRoutes for Backwards Compatability
reglim Nov 29, 2022
dc553b4
Migration: Remove Old Web
reglim Nov 29, 2022
14020f7
Migration: Fix Docker and Readme for the new web
reglim Nov 30, 2022
aa803aa
Migration: Fix Delete Page not cleared after successful delete
reglim Nov 30, 2022
b4f9e02
Migration: Add Tests for Project Repository
reglim Nov 30, 2022
50d2a34
Migration: Remove unused getDocsPath function
reglim Nov 30, 2022
d27e9c4
Migration: Add Search UI
reglim Nov 30, 2022
9780970
Migration: Fix Search returned everything when an empty query is used
reglim Dec 5, 2022
94c61f6
Migration: Add SearchBar to Header
reglim Dec 6, 2022
9e29bdf
Migration: Restructure Search Page
reglim Dec 6, 2022
a571620
Migration: Refactoring
reglim Dec 6, 2022
37c2882
Migration: Change Pipeline to run yarn test instead of yarn jest
reglim Dec 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ docat/__pycache__
docat/upload
docat/.tox
web/node_modules
web/build
web/.env*
2 changes: 1 addition & 1 deletion .github/workflows/docat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:

- name: run test suite
working-directory: web
run: yarn jest
run: yarn test

container-image:
runs-on: ubuntu-latest
Expand Down
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "none"
}
21 changes: 11 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
# building frontend
FROM node:16.14 as build-deps
FROM node:16.14 as frontend
WORKDIR /app/frontend
COPY web ./

# fix docker not following symlinks
COPY doc/getting-started.md ./src/assets/

RUN yarn install --frozen-lockfile
RUN yarn lint
RUN yarn run test:unit

# fix test not exiting by default
ARG CI=true
RUN yarn test

RUN yarn build

# setup Python
# TODO(Fliiiix): FastApi is broken in Python 3.11
# We need to wait for a fix:
# https://github.com/tiangolo/fastapi/issues/5048
FROM python:3.11.0-alpine3.15 AS backend

# configure docker container
Expand All @@ -29,12 +33,9 @@ COPY /docat/pyproject.toml /docat/poetry.lock /app/

# Install the application
WORKDIR /app/docat
RUN poetry install --no-root --no-ansi --no-dev
RUN poetry install --no-root --no-ansi --only main

# production
# TODO(Fliiiix): FastApi is broken in Python 3.11
# We need to wait for a fix:
# https://github.com/tiangolo/fastapi/issues/5048
FROM python:3.11.0-alpine3.15

# set up the system
Expand All @@ -46,7 +47,7 @@ RUN mkdir -p /var/docat/doc

# install the application
RUN mkdir -p /var/www/html
COPY --from=build-deps /dist /var/www/html
COPY --from=frontend /app/frontend/build /var/www/html
COPY docat /app/docat
WORKDIR /app/docat

Expand Down
16 changes: 15 additions & 1 deletion docat/docat/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
get_all_projects,
get_project_details,
index_all_projects,
is_forbidden_project_name,
remove_docs,
remove_file_index_from_db,
remove_version_from_version_index,
Expand Down Expand Up @@ -113,7 +114,12 @@ def get_project(project):
@app.get("/api/search", response_model=SearchResponse, status_code=status.HTTP_200_OK)
@app.get("/api/search/", response_model=SearchResponse, status_code=status.HTTP_200_OK)
def search(query: str):
query = query.lower()
query = query.lower().strip()

# an empty string would match almost everything
if not query:
return SearchResponse(projects=[], versions=[], files=[])

found_projects: list[SearchResultProject] = []
found_versions: list[SearchResultVersion] = []
found_files: list[SearchResultFile] = []
Expand Down Expand Up @@ -312,6 +318,10 @@ def upload(
docat_api_key: Optional[str] = Header(None),
db: TinyDB = Depends(get_db),
):
if is_forbidden_project_name(project):
response.status_code = status.HTTP_400_BAD_REQUEST
return ApiResponse(message=f'Project name "{project}" is forbidden, as it conflicts with pages in docat web.')

project_base_path = DOCAT_UPLOAD_FOLDER / project
base_path = project_base_path / version
target_file = base_path / file.filename
Expand Down Expand Up @@ -391,6 +401,10 @@ def claim(project: str, db: TinyDB = Depends(get_db)):
@app.put("/api/{project}/rename/{new_project_name}", response_model=ApiResponse, status_code=status.HTTP_200_OK)
@app.put("/api/{project}/rename/{new_project_name}/", response_model=ApiResponse, status_code=status.HTTP_200_OK)
def rename(project: str, new_project_name: str, response: Response, docat_api_key: str = Header(None), db: TinyDB = Depends(get_db)):
if is_forbidden_project_name(new_project_name):
response.status_code = status.HTTP_400_BAD_REQUEST
return ApiResponse(message=f'New project name "{new_project_name}" is forbidden, as it conflicts with pages in docat web.')

project_base_path = DOCAT_UPLOAD_FOLDER / project
new_project_base_path = DOCAT_UPLOAD_FOLDER / new_project_name

Expand Down
10 changes: 10 additions & 0 deletions docat/docat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ def calculate_token(password, salt):
return hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, 100000).hex()


def is_forbidden_project_name(name: str) -> bool:
"""
Checks if the given project name is forbidden.
The project name is forbidden if it conflicts with
a page on the docat website.
"""
name = name.lower().strip()
return name in ["upload", "claim", "delete", "search", "help"]


def get_all_projects(upload_folder_path: Path) -> Projects:
"""
Returns all projects in the upload folder.
Expand Down
23 changes: 23 additions & 0 deletions docat/tests/test_rename.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,26 @@ def test_rename_success(client_with_claimed_project):
assert len(claims_with_old_name) == 0
claims_with_new_name = table.search(Project.name == "new-project-name")
assert len(claims_with_new_name) == 1


def test_rename_rejects_forbidden_project_name(client_with_claimed_project):
"""
Names that conflict with pages in docat web are forbidden,
and renaming a project to such a name should fail.
"""

create_response = client_with_claimed_project.post(
"/api/some-project/1.0.0", files={"file": ("index.html", io.BytesIO(b"<h1>Hello World</h1>"), "plain/text")}
)
assert create_response.status_code == 201

with patch("os.rename") as rename_mock:
for project_name in ["upload", "claim", "delete", "Search ", "help"]:

rename_response = client_with_claimed_project.put(f"/api/some-project/rename/{project_name}", headers={"Docat-Api-Key": "1234"})
assert rename_response.status_code == 400
assert rename_response.json() == {
"message": f'New project name "{project_name}" is forbidden, as it conflicts with pages in docat web.'
}

assert rename_mock.mock_calls == []
19 changes: 19 additions & 0 deletions docat/tests/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,25 @@ def test_search_project_by_name_negative(client_with_claimed_project):
assert search_response.json() == {"projects": [], "versions": [], "files": []}


def test_search_ignores_empty_query(client_with_claimed_project):
"""
Search should return an empty result if the query is empty.
"""
create_project_response = client_with_claimed_project.post(
"/api/some-project/1.0.0",
files={"file": ("index.html", io.BytesIO(b"<h1>Hello World</h1>"), "plain/text")},
)
assert create_project_response.status_code == 201

search_response = client_with_claimed_project.get("/api/search?query=%20")
assert search_response.status_code == 200
assert search_response.json() == {"projects": [], "versions": [], "files": []}

search_response = client_with_claimed_project.get("/api/search?query=&")
assert search_response.status_code == 200
assert search_response.json() == {"projects": [], "versions": [], "files": []}


def test_search_finds_tag(client_with_claimed_project):
"""
Search should find a tag by name. (Partial match)
Expand Down
17 changes: 17 additions & 0 deletions docat/tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,20 @@ def test_fails_with_invalid_token(client_with_claimed_project):
assert response_data["message"] == "Docat-Api-Key token is not valid for some-project"

assert remove_mock.mock_calls == []


def test_upload_rejects_forbidden_project_name(client_with_claimed_project):
"""
Names that conflict with pages in docat web are forbidden,
and creating a project with such a name should fail.
"""

with patch("docat.app.remove_docs") as remove_mock:
for project_name in ["upload", "claim", "delete", "Search ", "help"]:
response = client_with_claimed_project.post(
f"/api/{project_name}/1.0.0", files={"file": ("index.html", io.BytesIO(b"<h1>Hello World</h1>"), "plain/text")}
)
assert response.status_code == 400
assert response.json() == {"message": f'Project name "{project_name}" is forbidden, as it conflicts with pages in docat web.'}

assert remove_mock.mock_calls == []
45 changes: 45 additions & 0 deletions web/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:react/recommended",
"standard-with-typescript"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx"
],
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"parserOptions": {
"project": [
"./tsconfig.json"
]
},
"rules": {
"@typescript-eslint/space-before-function-paren": "off"
}
},
{
"files": [
"src/react-app-env.d.ts"
],
"rules": {
"@typescript-eslint/triple-slash-reference": "off"
}
}
],
"parserOptions": {
"ecmaVersion": "latest"
},
"plugins": [
"react"
],
"rules": {}
}
36 changes: 22 additions & 14 deletions web/.gitignore
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
.DS_Store
node_modules
/dist
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# local env files
# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.prettierrc
.DS_Store
.env.local
.env.*.local
.env.development.local
.env.test.local
.env.production.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# local env files
.env
.env.local
.env.*.local
39 changes: 22 additions & 17 deletions web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@ yarn install [--pure-lockfile]

### Compiles and hot-reloads for development

Configure the backend connection by setting
port and host in `.env.development.local`.
Like this configuration for the host `127.0.0.1`
and the port `1337`.

Configure both the frontend port and the backend connection
by setting them in `.env.development.local`.
```sh
VUE_APP_BACKEND_PORT=1337
VUE_APP_BACKEND_HOST=127.0.0.1
PORT=8080
BACKEND_HOST=127.0.0.1
BACKEND_PORT=5000
```

```sh
yarn serve
yarn start
```

### Compiles and minifies for production
Expand All @@ -34,7 +32,13 @@ yarn build
yarn lint
```

### Basic Header Theeming
### Tests

```sh
yarn test
```

### Basic Header Theming

Not happy with the default Docat logo and header?
Just add your custom html header to the `/var/www/html/config.json` file.
Expand All @@ -43,21 +47,22 @@ Just add your custom html header to the `/var/www/html/config.json` file.
{ "headerHTML": "<h1>MyCompany</h1>" }
```

### Customize configuration

See [Configuration Reference](https://cli.vuejs.org/config/).


## Development

To mount the development `dist/` folder while working on the
web frontend, you can mount the `dist/` folder as a docker volume:

```sh
sudo docker run \
--detach \
--volume /path/to/doc:/var/docat/doc/ \
--volume /path/to/docat/web/dist:/var/www/html/ \
--publish 8000:80 \
docat
```

## Errors

If you get a 403 response when trying to read a version,
try changing the permissions of your docs folder on your host.

```sh
sudo chmod 777 /path/to/doc -r
```
5 changes: 0 additions & 5 deletions web/babel.config.js

This file was deleted.

3 changes: 0 additions & 3 deletions web/jest.config.js

This file was deleted.

Loading