Skip to content

Commit

Permalink
Merge pull request #53 from ani-hovhannisyan/feature/search-controller
Browse files Browse the repository at this point in the history
create search controller
  • Loading branch information
wowry committed Feb 5, 2022
2 parents b2e2524 + 643562f commit 8438608
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 43 deletions.
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

0 comments on commit 8438608

Please sign in to comment.