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

create search controller #53

Merged
merged 9 commits into from
Feb 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[flake8]
max-line-length=150
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"prettier.configPath": "./frontend/.prettierrc.json",
"prettier.ignorePath": "./frontend/.gitignore",
"python.analysis.extraPaths": [
"./backend/controller"
],
"python.linting.flake8Enabled": true,
"python.linting.enabled": true,
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ def construct_nodes_matrix(self):
matrix = []
# TODO: Implement logic
return matrix

@staticmethod
def get_graph_matrix(kanji: str):
# TODO: return acutual value
try:
graph_matrix = {"mainNode": "山", "subNodes": ["登", "水", "脈"]}
return [True, None, graph_matrix]
except Exception:
error_info = {"status_code": 400, "detail": "山 is not in data base"}
return [False, error_info, None]
10 changes: 10 additions & 0 deletions backend/controller/InfoController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class InfoController:
@staticmethod
def get_kanji_info(kanji: str):
# TODO: return acutual value
try:
kanji_info = {"onyomi": "さん", "detail": "やま"}
return [True, None, kanji_info]
except Exception:
error_info = {"status_code": 400, "detail": "山 is not in data base"}
return [False, error_info, None]
37 changes: 37 additions & 0 deletions backend/controller/SearchController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import re


class SearchController:
@staticmethod
def check_input(kanji):
print(len(kanji))

if kanji == "":
return SearchController._create_result(
False, 400, "Please include Kanji in the query parameters"
)
elif not SearchController._is_kanji(kanji):
return SearchController._create_result(
False, 400, "Only Kanji is permitted"
)
elif len(kanji) != 1:
return SearchController._create_result(
False, 400, "Only one character is allowed"
)

else:
return SearchController._create_result(True)

@staticmethod
def _create_result(is_success: bool, status: int = None, detail: str = None):
error_info = None if is_success else {"status_code": status, "detail": detail}

return [is_success, error_info]

@staticmethod
def _is_kanji(kanji):
p = re.compile(
"[\u2E80-\u2FDF\u3005-\u3007\u3400-\u4DBF"
"\u4E00-\u9FFF\uF900-\uFAFF\U00020000-\U0002EBEF]+"
)
return p.fullmatch(kanji)
23 changes: 23 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from fastapi import HTTPException
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from controller.SearchController import SearchController
from controller.GraphController import GraphController
from controller.InfoController import InfoController

app = FastAPI()

Expand All @@ -16,3 +20,22 @@
@app.get("/")
def read_root():
return {"message": "Hello from FastAPI!"}


@app.get("/kanji-visualize")
def read_kanji_vlsualize(kanji: str):
print(kanji)
is_success, error_info = SearchController.check_input(kanji)
print(error_info)
if not is_success:
raise HTTPException(**error_info)

is_success, error_info, graph_matrix = GraphController.get_graph_matrix(kanji)
if not is_success:
raise HTTPException(**error_info)

is_success, error_info, kanji_info = InfoController.get_kanji_info(kanji)
if not is_success:
raise HTTPException(**error_info)

return {"graphMatrix": graph_matrix, "kanjiInfo": kanji_info}
27 changes: 27 additions & 0 deletions backend/tests/test_searchController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from controller.SearchController import SearchController


def test_normal():
is_success, error_info = SearchController.check_input("山")
assert is_success


def test_invalid1():
is_success, error_info = SearchController.check_input("a")
assert not is_success
assert error_info == {"status_code": 400, "detail": "Only Kanji is permitted"}


def test_invalid2():
is_success, error_info = SearchController.check_input("")
assert not is_success
assert error_info == {
"status_code": 400,
"detail": "Please include Kanji in the query parameters",
}


def test_invalid3():
is_success, error_info = SearchController.check_input("登山")
assert not is_success
assert error_info == {"status_code": 400, "detail": "Only one character is allowed"}
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
"@types/node": "^16.7.13",
"@types/react": "^17.0.20",
"@types/react-dom": "^17.0.9",
"axios": "^0.25.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-hook-form": "^7.26.0",
"react-scripts": "5.0.0",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,4 @@ process.env.REACT_APP_API_PORT = "8000";

test("renders learn react link", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
58 changes: 18 additions & 40 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,26 @@
import React, { useEffect, useState } from "react";
import logo from "./logo.svg";
import "./App.css";
import React, { useState } from "react";
import SearchField from "./SearchField/SearchField";

function App() {
const [message, setMessage] = useState("");

useEffect(() => {
if (!process.env.REACT_APP_API_URL || !process.env.REACT_APP_API_PORT) {
console.error("URL of API is undefined");
return;
}
export type KanjiType = {
onyomi: string;
kunyomi: string;
};

fetch(
`${process.env.REACT_APP_API_URL}:${process.env.REACT_APP_API_PORT}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
mode: "cors",
}
)
.then((res) => res.json())
.then((data) => setMessage(data.message))
.catch((err) => console.error(err));
}, []);
//TODO: change correctly
export type GraphType = {
mainNode: string;
subNodes: string[];
};

function App() {
const [kanji, setKanji] = useState<undefined | KanjiType>();
const [graph, setGraph] = useState<undefined | GraphType>();
console.log(kanji);
console.log(graph);
return (
<div className="App">
<header className="App-header">
<h1>{message}</h1>
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<h1>Kanji Visualizer</h1>
<SearchField setKanji={setKanji} setGraph={setGraph}></SearchField>
</div>
);
}
Expand Down
61 changes: 61 additions & 0 deletions frontend/src/SearchField/SearchField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { useState } from "react";
import axios from "axios";
import { GraphType, KanjiType } from "../App";

type Props = {
setKanji: React.Dispatch<React.SetStateAction<KanjiType | undefined>>;
setGraph: React.Dispatch<React.SetStateAction<GraphType | undefined>>;
};

const regexp =
/([\u{3005}\u{3007}\u{303b}\u{3400}-\u{9FFF}\u{F900}-\u{FAFF}\u{20000}-\u{2FFFF}][\u{E0100}-\u{E01EF}\u{FE00}-\u{FE02}]?)/mu;
const SearchField = (props: Props) => {
const [kanjiInput, setKanjiInput] = useState<string>("");
const [error, setError] = useState<string>("Fill form");

const handleKanjiChange = (event: { target: { value: string } }) => {
const input = event.target.value;
if (typeof input != "string") {
setError("Invalid Input");
} else if (input.length !== 1) {
setError("Only one character is allowed");
} else if (!regexp.test(input)) {
setError("Input Only Kanji");
} else {
setError("");
}
setKanjiInput(input);
};

const handleSubmit = () => {
axios
.get(
`${process.env.REACT_APP_API_URL}:${process.env.REACT_APP_API_PORT}/kanji-visualize?kanji=${kanjiInput}`
)
.then((res) => {
const { data, status } = res;
console.log(status);
props.setKanji(data.kanjiInfo);
props.setGraph(data.graphMatrix);
})
.catch((error) => {
console.log(error.response);
setError(error.response.data.detail);
});
};

return (
<div>
<h2>Input Kanji</h2>
<div style={{ display: "flex" }}>
<input type="text" value={kanjiInput} onChange={handleKanjiChange} />
<button type="submit" onClick={handleSubmit} disabled={!!error}>
Search
</button>
</div>
<div>{error}</div>
</div>
);
};

export default SearchField;
14 changes: 13 additions & 1 deletion frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2373,6 +2373,13 @@ axe-core@^4.3.5:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5"
integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==

axios@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a"
integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==
dependencies:
follow-redirects "^1.14.7"

axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
Expand Down Expand Up @@ -4150,7 +4157,7 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2"
integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==

follow-redirects@^1.0.0:
follow-redirects@^1.0.0, follow-redirects@^1.14.7:
version "1.14.7"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
Expand Down Expand Up @@ -6938,6 +6945,11 @@ react-error-overlay@^6.0.10:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6"
integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==

react-hook-form@^7.26.0:
version "7.26.0"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.26.0.tgz#270ae0e7a27c01a57011efacd3d692c977eb1c5d"
integrity sha512-nSkCyJB5Ey5QUw3AGQp22JP7TNfPdyC4wqfmheH87NNsHhQwCZgGjexXdBfd7SRt4SHoVzbdPvu6kXG5sSs66Q==

"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
Expand Down