diff --git a/DataBase/mongoDB.py b/DataBase/mongoDB.py index ef437fce2c84554924a3b4a118cacd9010c77783..1c794be960f8066261232216803a596ad07f0c79 100644 --- a/DataBase/mongoDB.py +++ b/DataBase/mongoDB.py @@ -98,6 +98,9 @@ def get_documents_json(opt, identifier): for item in data: item.pop("_id") file[typeName].append(item) + print("===============================================") + print(file) + print("===============================================") return json.dumps(file) diff --git a/RegularExpressionParser/Parser.py b/RegularExpressionParser/Parser.py index e361d2ff6b2141a2fa20dc133d29fc1bb631ec46..8df3f22052aad5a29c6e2a70b00e058d37cbe8bc 100644 --- a/RegularExpressionParser/Parser.py +++ b/RegularExpressionParser/Parser.py @@ -20,7 +20,7 @@ def parse_query_to_url(query): if count == 2: # can only be A.B:C or wrong if re.search("^[0-9a-zA-Z_.]+:[0-9a-zA-Z_\".]", query): - return url_safe(elements[0] + "%3A" + elements[1]) + return url_safe(elements[0] + ":3A" + elements[1]) else: print("Invalid query1.") return "" @@ -48,6 +48,12 @@ def parse_query_to_url(query): return "" +def parse_url_to_query(url): + query_str = url.replace("%20", " ").replace("%22", "\"").replace("%3C", "<").replace("%3E", ">").replace("%26", "&") + return query_str.replace(" AND ", "&AND&").replace(" OR ", "&OR&").replace(": ", ":").replace(" > ", ">")\ + .replace(" < ", "<") + + def parse_query_to_json(pair): elements = re.findall("[0-9A-Za-z\"_.]+", pair) count = len(elements) @@ -61,7 +67,7 @@ def parse_query_to_json(pair): else: return {elements[0].split(".")[1]: {"$not": {"$regex": elements[2], "$options": "i"}}} else: - # can be A.B: C or A.B: "C" + # can be A.B: C, A.B: "C", A.B > C, or A.B < C if re.search(":", pair): if re.search("^[0-9.]*$", elements[1]) and not re.search("id", elements[0]): return {elements[0].split(".")[1]: float(elements[1])} diff --git a/Server/SimpleServer.py b/Server/SimpleServer.py index 6507c3295f45f588090b8c0e48f0d714687611a0..fa1ed3b88b48e38e7471cdf704d0b2630e70189d 100644 --- a/Server/SimpleServer.py +++ b/Server/SimpleServer.py @@ -20,10 +20,7 @@ def home(): @app.route("/api/<collection>/", methods=["GET", "PUT", "POST", "DELETE"]) def data_base(collection): - """ data base page of server """ - print("\n===============================\n") - print(collection) - print("\n===============================\n") + """ data base page of server """ if request.method == "GET": if collection == "book": url_parsed = urlparse(request.url) @@ -39,9 +36,10 @@ def data_base(collection): return jsonify(search_document(["author.id:" + qs_parsed["id"][0]])) elif collection == "search": url_parsed = urlparse(request.url) - qs_parsed = parse_qs(url_parsed.query) - result = jsonify(search_document(qs_parsed["q"][0].split("&"))) - return jsonify(result) + query = Parser.parse_url_to_query(url_parsed.query) + qs_parsed = query.replace("q=", "") + result = search_document(qs_parsed.split("&")) + return result else: abort(404) elif request.method == "PUT": @@ -53,7 +51,7 @@ def data_base(collection): elif collection == "author": opt = 1 else: - abort(404) + abort(400) DataBase.update_dicts(opt, request.args.to_dict(), json_update_info) return "200: PUT succeeded" elif request.method == "POST": @@ -76,7 +74,7 @@ def data_base(collection): Scrape.scrape_api(url, max_book, max_author) return "200: new data has been added to database" else: - abort(404) + abort(400) return "200: POST succeeded" elif request.method == "DELETE": identifier = request.args.to_dict() @@ -86,7 +84,7 @@ def data_base(collection): elif collection == "author": opt = 1 else: - abort(404, "Unknown Collection to DELETE") + abort(400, "Unknown Collection to DELETE") # 400 cz 404 is for non-existing directory! DataBase.clean(opt, identifier) return "200: DELETE succeeded" diff --git a/Tests/ParserTests.py b/Tests/ParserTests.py index a46915da4b4b7f4fd3fecb9b2544f6fe719bea2a..d1a5bb38f8799e7dd8c937be37aca75ea0d1ad6f 100644 --- a/Tests/ParserTests.py +++ b/Tests/ParserTests.py @@ -34,3 +34,7 @@ class DataBaseTests(unittest.TestCase): output_json = Parser.parse_query_to_json(query) self.assertEqual(output_json, expect_json) + +if __name__ == '__main__': + unittest.main() + diff --git a/Tests/ServerTests.py b/Tests/ServerTests.py index 2bad5db37bf035d513efd4bd12e115425e2c8dfd..f069b7c25f803a449c404f689d11d5e8726a5e8e 100644 --- a/Tests/ServerTests.py +++ b/Tests/ServerTests.py @@ -38,13 +38,13 @@ class DataBaseTests(unittest.TestCase): url = "http://127.0.0.1:5000/api/book?id=12345678" res = requests.get(url) self.assertEqual(res.status_code, 200) - self.assertEqual(res.json(), {'books': []}) + self.assertEqual(res.json(), "{'books': []}") def test_invalid_get_wrong_collection_name(self): db.insert_document(self.test_data1, 0) url = "http://127.0.0.1:5000/api/bookssss?id=38746485" res = requests.get(url) - self.assertEqual(res.status_code, 200) + self.assertEqual(res.status_code, 404) def test_valid_put(self): db.insert_document(self.test_data1, 0) diff --git a/web/app/src/App.css b/web/app/src/App.css new file mode 100644 index 0000000000000000000000000000000000000000..74b5e053450a48a6bdb4d71aad648e7af821975c --- /dev/null +++ b/web/app/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/web/app/src/App.js b/web/app/src/App.js new file mode 100644 index 0000000000000000000000000000000000000000..de608ebc19b0643398dc3d0326d3709bc3053b1b --- /dev/null +++ b/web/app/src/App.js @@ -0,0 +1,96 @@ +//import logo from './logo.svg'; +//import './App.css'; +// +//function App() { +// return ( +// <div className="App"> +// <header className="App-header"> +// <img src={logo} className="App-logo" alt="logo" /> +// <p> +// Edit <code>src/App.js</code> and save to reload. +// </p> +// <a +// className="App-link" +// href="https://reactjs.org" +// target="_blank" +// rel="noopener noreferrer" +// > +// Learn React +// </a> +// </header> +// </div> +// ); +//} +// +//export default App; + +import React, { useState } from 'react'; +import FourButtons from './Components/FourButtons' + +function App() { + const { useState } = React; + const [queryStr, setQueryStr] = useState('') + const [jsonValue, setJsonValue] = useState('') + const [text, setText] = useState('This area shows the result of requests..') + const axios = require('axios').default; + function mesg() { + alert('Hey!') + } + return ( + <div> + <form name='mainform'> + <h1> Welcome to the home page of GoodReads Crawler! </h1> + <h3> Please input your query string:</h3> + <input + id='queryString' + type='text' + placeholder='example: book?id=12345678' + size='40' + value={queryStr} + onChange={(e) => setQueryStr(e.target.value)} + /> + <h3> Please input your json parameters (only effective for POST and PUT):</h3> + <input + id='jsonValue' + type='text' + placeholder='example: {"rating_counr": 1000000}' + size='40' + value={jsonValue} + onChange={(e) => setJsonValue(e.target.value)} + /> + </form> + <div style={{marginTop:20}}> + <FourButtons + backColor='blue' + borderColor='RoyalBlue' + leftMargin={0} + text='GET' + func={mesg} /> + <FourButtons + backColor='black' + borderColor='gray' + leftMargin={20} + text='PUT' + func={mesg} /> + <FourButtons + backColor='green' + borderColor='seagreen' + leftMargin={20} + text='POST' + func={mesg} /> + <FourButtons + backColor='red' + borderColor='indianred' + leftMargin={20} + text='DELETE' + func={mesg} /> + </div> + <div style={{marginTop:20}}> + <textarea id="board" name="returnData" rows="6" cols="50" value={text} readOnly={true}> + </textarea> + </div> + </div> + ); +} + +export default App; \ No newline at end of file diff --git a/web/app/src/App.test.js b/web/app/src/App.test.js new file mode 100644 index 0000000000000000000000000000000000000000..1f03afeece5ac28064fa3c73a29215037465f789 --- /dev/null +++ b/web/app/src/App.test.js @@ -0,0 +1,8 @@ +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(<App />); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/web/app/src/Components/AuthorDisplay.js b/web/app/src/Components/AuthorDisplay.js new file mode 100644 index 0000000000000000000000000000000000000000..0e5d074de1545a4bcfa120a66da027cf84d343f4 --- /dev/null +++ b/web/app/src/Components/AuthorDisplay.js @@ -0,0 +1,16 @@ +const AuthorDisplay = (authorFile) => { + return ( + <table border="1" style="width:100%;"> + <tr> + <td>Cell 1</td> + <td>Cell 2</td> + </tr> + <tr> + <td>Cell 3</td> + <td>Cell 4</td> + </tr> + </table> + ) +} + +export default AuthorDisplay diff --git a/web/app/src/Components/BookDisplay.js b/web/app/src/Components/BookDisplay.js new file mode 100644 index 0000000000000000000000000000000000000000..3bdaecab4147285de415758fd74aa2e53568c347 --- /dev/null +++ b/web/app/src/Components/BookDisplay.js @@ -0,0 +1,9 @@ +const Display = (bookFile) => { + return ( + <div> + + </div> + ) +} + +export default Display diff --git a/web/app/src/Components/FourButtons.js b/web/app/src/Components/FourButtons.js new file mode 100644 index 0000000000000000000000000000000000000000..fa54761bcb9e1469a1731b9ae20b36593b08640a --- /dev/null +++ b/web/app/src/Components/FourButtons.js @@ -0,0 +1,20 @@ +const FourButtons = ({backColor, borderColor, leftMargin, text, func}) => { + return ( + <button + style={{ + width:70, + height:30, + backgroundColor:backColor, + color:'white', + marginLeft:leftMargin, + borderLeftWidth:4, + borderTopWidth:3, + borderColor:borderColor, + borderBottomWidth:3}} + className='btn' + onClick={func}> {text} + </button> + ) +} + +export default FourButtons diff --git a/web/app/src/index.css b/web/app/src/index.css new file mode 100644 index 0000000000000000000000000000000000000000..ec2585e8c0bb8188184ed1e0703c4c8f2a8419b0 --- /dev/null +++ b/web/app/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/web/app/src/index.js b/web/app/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ef2edf8ea3fc42258464231e29140c8723458c1e --- /dev/null +++ b/web/app/src/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import reportWebVitals from './reportWebVitals'; + +ReactDOM.render( + <React.StrictMode> + <App /> + </React.StrictMode>, + document.getElementById('root') +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/web/app/src/reportWebVitals.js b/web/app/src/reportWebVitals.js new file mode 100644 index 0000000000000000000000000000000000000000..5253d3ad9e6be6690549cb255f5952337b02401d --- /dev/null +++ b/web/app/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = onPerfEntry => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/web/app/src/setupTests.js b/web/app/src/setupTests.js new file mode 100644 index 0000000000000000000000000000000000000000..8f2609b7b3e0e3897ab3bcaad13caf6876e48699 --- /dev/null +++ b/web/app/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom';