Skip to content

Commit

Permalink
Cleanup code (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
aditeyabaral committed Jun 26, 2023
1 parent 04ddf4c commit e6197da
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 41 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ __pycache__/
github-markdown-css/
images/
*.log
README.html
README.html
README_tmp*
45 changes: 36 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ On authentication, it returns the following parameters in a JSON object. If the
profile data was requested, the response's `profile` key will store a dictionary with a user's profile information.
**On an unsuccessful sign-in, this field will not exist**.

| **Field** | **Type** | **Description** |
|-------------|-----------------|--------------------------------------------------------------------------|
| `status` | `boolean` | A flag indicating whether the overall request was successful |
| `profile` | `ProfileObject` | A nested map storing the profile information, returned only if requested |
| `message` | `str` | A message that provides information corresponding to the status |
| `timestamp` | `datetime` | A timezone offset timestamp indicating the time of authentication |
| `error` | `str` | The error name and stack trace, if an application side error occurs |
| **Field** | **Type** | **Description** |
|-------------------------------|---------------------------------|---------------------------------------------------------------------------------------------|
| `status` | `boolean` | A flag indicating whether the overall request was successful |
| `profile` | `ProfileObject` | A nested map storing the profile information, returned only if requested |
| `know_your_class_and_section` | `KnowYourClassAndSectionObject` | A nested map storing the profile information from PESU's Know Your Class and Section Portal |
| `message` | `str` | A message that provides information corresponding to the status |
| `timestamp` | `datetime` | A timezone offset timestamp indicating the time of authentication |
| `error` | `str` | The error name and stack trace, if an application side error occurs |

#### Profile Object

Expand All @@ -49,6 +50,20 @@ profile data was requested, the response's `profile` key will store a dictionary
| `campus_code` | The integer code of the campus (1 for RR and 2 for EC) |
| `campus` | Abbreviation of the user's campus name |

#### KnowYourClassAndSectionObject

| **Field** | **Description** |
|------------------|----------------------------------------------------------------|
| `prn` | PRN of the user |
| `srn` | SRN of the user |
| `name` | Name of the user |
| `class` | Current semester that the user is in |
| `section` | Section of the user |
| `cycle` | Physics Cycle or Chemistry Cycle, if the user is in first year |
| `department` | Abbreviation of the branch along with the campus of the user |
| `branch` | Abbreviation of the branch that the user is pursuing |
| `institute_name` | The name of the campus that the user is studying in |

<details><summary>Here is an example using Python</summary>

#### Request
Expand Down Expand Up @@ -84,6 +99,17 @@ print(response.json())
"campus_code": 1,
"campus": "RR"
},
"know_your_class_and_section": {
"prn": "PES1201800001",
"srn": "PES1201800001",
"name": "Johnny Blaze",
"class": "Sem-1",
"section": "Section A",
"cycle": "NA",
"department": "CSE (RR Campus)",
"branch": "CSE",
"institute_name": "PES University (Ring Road)"
},
"message": "Login successful.",
"timestamp": "2023-06-18 20:57:59.979374+05:30"
}
Expand All @@ -94,10 +120,11 @@ print(response.json())
## Interactive Mode

You can also use interactive mode which will spawn a browser window and allow the user to sign in to PESU Academy. Send
a request to the `authenticateInteractive` endpoint with the `profile` query parameter set to `true` and the API will return
a request to the `authenticateInteractive` endpoint with the `profile` query parameter set to `true` and the API will
return
a JSON object with the user's profile information.

> :warning: **Warning:** This will only work if the API is running on the same server as the client.
> :warning: **Warning:** This will only work if the API is running on the same server as the client.
<details><summary>Here is an example using Python</summary>

Expand Down
10 changes: 6 additions & 4 deletions app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import logging
import os
import re
import traceback

import gh_md_to_html
Expand All @@ -22,14 +23,17 @@


def convert_readme_to_html():
html = gh_md_to_html.main("README.md").strip()
readme_content = open("README.md").read().strip()
readme_content = re.sub(r":\w+: ", "", readme_content)
with open("README_tmp.md", "w") as f:
f.write(readme_content)
html = gh_md_to_html.main("README_tmp.md").strip()
with open("README.html", "w") as f:
f.write(html)


@app.route("/")
def index():
# TODO: Fix this - replace with SwaggerUI
try:
if "README.html" not in os.listdir():
convert_readme_to_html()
Expand Down Expand Up @@ -75,8 +79,6 @@ def authenticate_interactive():
return json.dumps(authentication_result), 200


# TODO: Add routes for all possible auth methods

if __name__ == "__main__":
pesu_academy = PESUAcademy()
app.run(host="0.0.0.0", port=5000)
11 changes: 0 additions & 11 deletions app/example.py

This file was deleted.

39 changes: 23 additions & 16 deletions app/pesu.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self):
self.chrome: Optional[webdriver.Chrome] = None
self.chrome_options: Optional[webdriver.ChromeOptions] = None

self.branch_short_code_map = {
self.branch_short_code_map: dict[str, str] = {
"Computer Science and Engineering": "CSE",
"Electronics and Communication Engineering": "ECE",
"Mechanical Engineering": "ME",
Expand All @@ -29,7 +29,7 @@ def __init__(self):
}

def init_chrome(self, headless: bool = True):
logging.info("Initializing Chrome")
logging.info(f"Initializing Chrome with headless={headless}")
self.chrome_options = webdriver.ChromeOptions()

if headless:
Expand Down Expand Up @@ -62,7 +62,7 @@ def init_chrome(self, headless: bool = True):
def map_branch_to_short_code(self, branch: str) -> Optional[str]:
return self.branch_short_code_map.get(branch)

def get_profile_details_selenium(self, username: Optional[str] = None) -> dict[str, Any]:
def get_profile_information_from_selenium(self, username: Optional[str] = None) -> dict[str, Any]:
try:
logging.info("Navigating to profile data")
menu_options = self.chrome.find_elements(By.CLASS_NAME, "menu-name")
Expand Down Expand Up @@ -105,7 +105,7 @@ def get_profile_details_selenium(self, username: Optional[str] = None) -> dict[s
self.chrome.quit()
return {"status": False, "message": "Unable to fetch profile data.", "error": str(e)}

def get_profile_details_requests(
def get_profile_information_from_requests(
self,
session: requests_html.HTMLSession,
username: Optional[str] = None
Expand Down Expand Up @@ -155,11 +155,15 @@ def get_profile_details_requests(
return {"status": True, "profile": profile, "message": "Login successful."}

@staticmethod
def get_profile_know_your_class_and_section(
session: requests_html.HTMLSession,
csrf_token: Optional[str],
username: Optional[str] = None
def get_know_your_class_and_section(
username: str,
session: Optional[requests_html.HTMLSession] = None,
csrf_token: Optional[str] = None,
) -> dict[str, Any]:

if not session:
session = requests_html.HTMLSession()

if not csrf_token:
home_url = "https://www.pesuacademy.com/Academy/"
response = session.get(home_url)
Expand Down Expand Up @@ -189,7 +193,7 @@ def get_profile_know_your_class_and_section(
"loginId": username
}
)
except Exception as e:
except Exception:
logging.error(f"Unable to get profile from Know Your Class and Section: {traceback.format_exc()}")
return {}

Expand All @@ -209,6 +213,7 @@ def authenticate_selenium_non_interactive(
password: str,
profile: bool = False
) -> dict[str, Any]:
logging.warning("This method is deprecated and will be removed in future versions.")

self.init_chrome()
try:
Expand Down Expand Up @@ -250,7 +255,10 @@ def authenticate_selenium_non_interactive(
logging.info("Login successful")

if profile:
return self.get_profile_details_selenium(username)
result = self.get_profile_information_from_selenium(username)
know_your_class_and_section_data = self.get_know_your_class_and_section(username)
result["know_your_class_and_section"] = know_your_class_and_section_data
return result
else:
self.chrome.quit()
return {"status": status, "message": "Login successful."}
Expand All @@ -270,7 +278,6 @@ def authenticate_selenium_interactive(self, profile: bool = False) -> dict[str,
return {"status": False, "message": "Unable to connect to PESU Academy.", "error": str(e)}

# wait for user to login manually
status = False
try:
logging.info("Waiting for user to login manually")
WebDriverWait(self.chrome, 90).until(
Expand All @@ -283,7 +290,7 @@ def authenticate_selenium_interactive(self, profile: bool = False) -> dict[str,
return {"status": False, "message": "Unable to find the login form.", "error": str(e)}

if profile:
return self.get_profile_details_selenium()
return self.get_profile_information_from_selenium()
else:
self.chrome.quit()
return {"status": status, "message": "Login successful."}
Expand Down Expand Up @@ -332,11 +339,11 @@ def authenticate(self, username: str, password: str, profile: bool = False) -> d
csrf_token = soup.find("meta", attrs={"name": "csrf-token"})["content"]

if profile:
result = self.get_profile_details_requests(session, username)
know_your_class_and_section_data = self.get_profile_know_your_class_and_section(
result = self.get_profile_information_from_requests(session, username)
know_your_class_and_section_data = self.get_know_your_class_and_section(
username,
session,
csrf_token,
username
csrf_token
)
result["know_your_class_and_section"] = know_your_class_and_section_data
return result
Expand Down

0 comments on commit e6197da

Please sign in to comment.