From 5cd31778c419a43d61e8e4e967f2328e399f1817 Mon Sep 17 00:00:00 2001 From: Kosh Date: Sun, 15 Oct 2023 18:54:06 +0530 Subject: [PATCH] Interacting with data with rest api --- backend/api-docs.txt | 264 ++++++++++++++++++++++++++++++---- backend/rest_api.py | 336 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 567 insertions(+), 33 deletions(-) diff --git a/backend/api-docs.txt b/backend/api-docs.txt index 84f0cdc..0b5badd 100644 --- a/backend/api-docs.txt +++ b/backend/api-docs.txt @@ -1,11 +1,19 @@ +WARNING:- + Do NOT use this api for ANY reason EXCEPT if usage is ONLY local, i.e., + this api is NOT built for usage over an external network and doing so + WILL NOT BE SECURE + +Note:- Server throws 405 METHOD NOT ALLOWED if the url is mistyped _____________________ Login:- + + WARNING:- + If login is used when another user is logged in, + the original user is automatically logged out. + URL:- /login - Method:- POST - Data Type:- Form Data - Data content:- { user_name: "", password: "" @@ -15,102 +23,111 @@ Login:- 200 OK:- Data:- No Note:- Assume login completed. - 400 Bad Request:- Content Type:- text/plain Note:- user_name or password not given a Form Data. Data:- What is missing will be mentioned. - 403 Forbidden:- Content Type:- text/plain Note:- user_name or password is wrong, can display the response data to user. Data:- What is wrong will be mentioned, text that can be displayed on the screen. Example:- - formData = new FormData(); - formData.append('name', 'John'); - formData.append('password', 'John123'); + formData = new FormData() + formData.append('user_name', 'John') + formData.append('password', 'John123') fetch( "/login", { body: formData, method: "post" } - ); - + ) This will give a response status 200 with no data if login is done. This will return a 403 if the user gave wrong name or password. _____________________ +_____________________ +Logout:- + URL:- /logout + Method:- POST + Data:- None + + Response:- + 200 OK:- + Data:- No + Note:- Assume Success. + 403 Forbidden:- + Content Type:- text/plain + Note:- User is not logged in. + Data:- What is wrong will be mentioned. + This text that can be displayed on the screen. +_____________________ + + _____________________ Add User:- URL:- /add_user - Method:- POST - Data Type:- Form Data - Data content:- { user_name: "", password: "" } + Note:- Does not login the user Response:- 200 OK:- Data:- No Note:- Assume success. - 400 Bad Request:- Content Type:- text/plain Note:- user_name or password not given a Form Data. Data:- What is missing will be mentioned. - 403 Forbidden:- Content Type:- text/plain - Note:- user_name is exists, can display the response data to user. - Data:- Text that can be displayed on the screen. + Note:- user_name exists, can display the response data to user. + Data:- What is wrong will be mentioned. + This text that can be displayed on the screen. Example:- - formData = new FormData(); - formData.append('name', 'John'); - formData.append('password', 'John123'); + formData = new FormData() + formData.append('user_name', 'John') + formData.append('password', 'John123') fetch( - "/login", + "/add_user", { body: formData, method: "post" } - ); - - This will give a response status 200 with no data if login is done. - This will return a 403 if the user gave wrong name or password. + ) + This will give a response status 200 with no data if a user is added. + This will return a 403 if the user gave a existing name. _____________________ _____________________ Get Data:- URL:- /get_data - Method:- POST - Data:- None + Prerequisites:- Login Response:- 200 OK:- - Data:- All user data - Note:- - data:- { + Data:- { entry_name: { field_name: field_value } } + Content Type:- text/json 403 Forbidden:- Data:- Text that can be directly displayed to the user Note:- Not logged in - Example:- + Example Response:- { "Amazon": { "Username": "Kosh", @@ -123,3 +140,188 @@ Get Data:- } } _____________________ + + +_____________________ +Change Password:- + URL:- /change_password + Method:- POST + Data:- New Password + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- password not given. :< + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in +_____________________ + + +_____________________ +Add entry:- + URL:- /add_entry + Method:- POST + Data:- { + entry_name: "", + fields: { + field_name1: "", + field_name2: "", + ... + } + } + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- entry_name or fields not given or fields cannot be converted to json + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in or entry_name already exists + + Example:- + formData = new FormData() + formData.append('entry_name', 'Amazon') + formData.append( + 'fields', + JSON.stringify( + { + "User Name": "Kosh", + password: "1234" + } + ) + ) + fetch( + "/entry_name", + { + body: formData, + method: "post" + } + ) + This will give a response status 200 with no data if the data is entered. + This will return a 403 if the user is not logged in or entry_name already exists. +_____________________ + + +_____________________ +Delete Entry:- + URL:- /delete_entry + Method:- POST + Data:- entry_name + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- entry_name not given + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in or entry_name does not exist +_____________________ + + +_____________________ +Edit Entry Name:- + URL:- /edit_entry_name + Method:- POST + Data:- old_entry_name, new_entry_name + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- old_entry_name or new_entry_name not given + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in or old_entry_name does not exist or new_entry_name exists +_____________________ + + +_____________________ +Add Field:- + URL:- /add_field + Method:- POST + Data:- entry_name, field_name, field_value + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- entry_name, field_name or field_value are + not given or fields cannot be converted to json + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in or field_name already exists or entry_name does not exist +_____________________ + + +_____________________ +Edit Field Name:- + URL:- /edit_field_name + Method:- POST + Data:- entry_name, old_field_name, new_field_name + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- old_field_name or new_field_name not given + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in or old_field_name does not exist or new_field_name exists +_____________________ + + +_____________________ +Edit Field Value:- + URL:- /edit_field_value + Method:- POST + Data:- entry_name, field_name, field_value + Prerequisites:- Login + + Response:- + 200 OK:- + Data:- None + Note:- Assume success + 400 Bad Request:- + Data:- Error text + Content Type:- text/plain + Note:- entry_name, field_name or field_value not given + 403 Forbidden:- + Data:- Text that can be directly displayed to the user + Content Type:- text/plain + Note:- Not logged in or field_name does not exist +_____________________ + diff --git a/backend/rest_api.py b/backend/rest_api.py index ae02b43..38478b3 100644 --- a/backend/rest_api.py +++ b/backend/rest_api.py @@ -1,8 +1,9 @@ from os import mkdir, path +import json from flask import Flask, request, send_file, abort, Response from werkzeug.datastructures import ImmutableMultiDict import appdirs -import json + from data_handler import DataHandler @@ -73,6 +74,21 @@ class QueryHandler: return Response(status=200) + @staticmethod + @app.post("/logout") + def logout() -> Response: + """ + Logs the user out + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + QueryHandler.__data_handler = None + return Response(status=200) + @staticmethod @app.post("/add_user") def add_user() -> Response: @@ -119,5 +135,321 @@ class QueryHandler: return Response( json.dumps(QueryHandler.__data_handler.get_data()), 200, - content_type="application/json" + content_type="text/json" ) + + @staticmethod + @app.post("/change_password") + def change_password() -> Response: + """ + Change the password of the user. + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "password" not in data: + return Response( + "password is not given", + 400, + content_type="text/plain" + ) + + QueryHandler.__data_handler.change_password(data["password"]) + + return Response(status=200) + + @staticmethod + @app.post("/add_entry") + def add_entry() -> Response: + """ + Add a new entry to the data + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "entry_name" not in data: + return Response( + "entry_name is not given", + 400, + content_type="text/plain" + ) + if "fields" not in data: + return Response( + "fields is not given", + 400, + content_type="text/plain" + ) + entry_name: str = data["entry_name"] + try: + fields: dict = json.loads(data["fields"]) + except json.decoder.JSONDecodeError: + return Response( + f"The json-string provided is wrong {data['fields']}", + 400, + content_type="text/plain" + ) + try: + QueryHandler.__data_handler.add_entry(entry_name, fields) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200) + + @staticmethod + @app.post("/delete_entry") + def delete_entry() -> Response: + """ + Delete Entry for the logged in user + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "entry_name" not in data: + return Response( + "entry_name is not given", + 400, + content_type="text/plain" + ) + entry_name: str = data["entry_name"] + try: + QueryHandler.__data_handler.delete_entry(entry_name) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200) + + @staticmethod + @app.post("/edit_entry_name") + def edit_entry_name() -> Response: + """ + Delete Entry for the logged in user + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "old_entry_name" not in data: + return Response( + "old_entry_name is not given", + 400, + content_type="text/plain" + ) + if "new_entry_name" not in data: + return Response( + "new_entry_name is not given", + 400, + content_type="text/plain" + ) + try: + QueryHandler.__data_handler.edit_entry_name( + data["old_entry_name"], data["new_entry_name"] + ) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200) + + @staticmethod + @app.post("/add_field") + def add_field() -> Response: + """ + Add a field to the entry + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "entry_name" not in data: + return Response( + "entry_name is not given", + 400, + content_type="text/plain" + ) + if "field_name" not in data: + return Response( + "field_name is not given", + 400, + content_type="text/plain" + ) + if "field_value" not in data: + return Response( + "field_value is not given", + 400, + content_type="text/plain" + ) + try: + QueryHandler.__data_handler.add_field( + data["entry_name"], + data["field_name"], + data["field_value"] + ) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200) + + @staticmethod + @app.post("/delete_field") + def delete_field() -> Response: + """ + Delete a field from a entry + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "entry_name" not in data: + return Response( + "entry_name is not given", + 400, + content_type="text/plain" + ) + if "field_name" not in data: + return Response( + "field_name is not given", + 400, + content_type="text/plain" + ) + try: + QueryHandler.__data_handler.delete_field( + data["entry_name"], + data["field_name"] + ) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200) + + @staticmethod + @app.post("/edit_field_name") + def edit_field_name() -> Response: + """ + Change the field name in a entry + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "entry_name" not in data: + return Response( + "entry_name is not given", + 400, + content_type="text/plain" + ) + if "old_field_name" not in data: + return Response( + "old_field_name is not given", + 400, + content_type="text/plain" + ) + if "new_field_name" not in data: + return Response( + "new_field_name is not given", + 400, + content_type="text/plain" + ) + try: + QueryHandler.__data_handler.edit_field_name( + data["entry_name"], + data["old_field_name"], + data["new_field_name"] + ) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200) + + @staticmethod + @app.post("/edit_field_value") + def edit_field_value() -> Response: + """ + Change the value of a field + """ + if QueryHandler.__data_handler is None: + return Response( + "Not logged in", + 403, + content_type="text/plain" + ) + + data: ImmutableMultiDict[str, str] = request.form + if "entry_name" not in data: + return Response( + "entry_name is not given", + 400, + content_type="text/plain" + ) + if "field_name" not in data: + return Response( + "field_name is not given", + 400, + content_type="text/plain" + ) + if "field_value" not in data: + return Response( + "field_value is not given", + 400, + content_type="text/plain" + ) + try: + QueryHandler.__data_handler.edit_field_value( + data["entry_name"], + data["field_name"], + data["field_value"] + ) + except ValueError as value_error: + return Response( + str(value_error), + 403, + content_type="text/plain" + ) + return Response(status=200)