Implementing retrieving blog data
This commit is contained in:
parent
faa718c7d5
commit
107df32af9
|
|
@ -2,7 +2,9 @@ import os
|
|||
import datetime
|
||||
|
||||
import psycopg2
|
||||
from orgparse import loads
|
||||
|
||||
import userHandler
|
||||
import orgHandler
|
||||
import dbHandler
|
||||
|
||||
|
|
@ -13,6 +15,70 @@ def debugPrint(msg: str) -> None:
|
|||
if debug:
|
||||
print("(BLOG HANDLER) PRINT: " + msg)
|
||||
|
||||
def checkIDExistence(dbConnection: psycopg2.extensions.connection, blogID: int) -> bool:
|
||||
return dbHandler.checkFieldValueExistence(dbConnection, "blogs", "id", blogID)
|
||||
|
||||
def getBlogCardRange(dbConnection: psycopg2.extensions.connection, rangeStart: int, rangeEnd: int, latestRecords = True) -> dict:
|
||||
records = dbHandler.getRowRangeByID(dbConnection, "blogs", rangeStart, rangeEnd, latestRecords)
|
||||
recordsDictionary = {}
|
||||
for index, record in enumerate(records):
|
||||
datePostedStr = record[3].strftime("%G-%m-%d %X")
|
||||
# 0 index reserved for success/message status
|
||||
recordsDictionary[index+1] = {
|
||||
"blogID": record[0],
|
||||
"authorInfo": {
|
||||
"ID": record[1],
|
||||
"username": userHandler.getUserInfoByID(dbConnection, record[1], "username"),
|
||||
"firstName": userHandler.getUserInfoByID(dbConnection, record[1], "firstname"),
|
||||
"lastName": userHandler.getUserInfoByID(dbConnection, record[1], "lastname")
|
||||
},
|
||||
"categoryID": record[2],
|
||||
"datePosted": datePostedStr,
|
||||
"title": record[4],
|
||||
"description": record[5]
|
||||
}
|
||||
return recordsDictionary
|
||||
|
||||
|
||||
def getBlogTitle(blogID: int) -> str:
|
||||
debugPrint("Attempting to retrieve blog title of blog ID " + str(blogID))
|
||||
try:
|
||||
fileData = open(blogDir + "/" + str(blogID) + "/" + str(blogID) + ".org", 'r')
|
||||
title = orgHandler.checkAndRetrieveMetadata(fileData, "TITLE")
|
||||
if title:
|
||||
return title
|
||||
except Exception as error:
|
||||
debugPrint("Error getting blog title! " + repr(error))
|
||||
|
||||
def getBlogDescription(blogID: int) -> str:
|
||||
debugPrint("Attempting to retrieve blog description of blog ID " + str(blogID))
|
||||
try:
|
||||
fileData = open(blogDir + "/" + str(blogID) + "/" + str(blogID) + ".org", 'r')
|
||||
orgRoot = loads(fileData.read())
|
||||
|
||||
fileData.readline()
|
||||
shortDescription = orgHandler.checkAndRetrieveMetadata(fileData, "DESCRIPTION")
|
||||
if not shortDescription:
|
||||
debugPrint("No valid description found, will generate a placeholder from the text itself...")
|
||||
firstText = orgRoot[1].body
|
||||
shortDescription = (firstText[:60] + "...") if len(firstText) > 60 else firstText
|
||||
return shortDescription
|
||||
except Exception as error:
|
||||
debugPrint("Error getting blog description! Unexpected error: " + repr(error) + ".")
|
||||
|
||||
def getBlogContentsHTML(blogID: int) -> str:
|
||||
try:
|
||||
debugPrint("Attempting to retrieve blog contents of blogID " + str(blogID) + "...")
|
||||
FullBlogDir = blogDir + "/" + str(blogID)
|
||||
HTMLFileData = open(FullBlogDir + "/" + str(blogID) + ".html", 'r')
|
||||
HTMLFileContents = HTMLFileData.read()
|
||||
HTMLFileData.close()
|
||||
return HTMLFileContents
|
||||
except Exception as error:
|
||||
msg = "Retrieve blog contents of blogID " + str(blogID) + " failed! Unexpected error: " + repr(error) + "."
|
||||
debugPrint(msg)
|
||||
return msg
|
||||
|
||||
# Returns new Blog ID
|
||||
def createBlogEntry(dbConnection: psycopg2.extensions.connection, userID: int, categoryID: int) -> int:
|
||||
datePosted = datetime.datetime.now()
|
||||
|
|
@ -24,6 +90,12 @@ def createBlogEntry(dbConnection: psycopg2.extensions.connection, userID: int, c
|
|||
[userID, categoryID, datePostedStr])
|
||||
return newRow[0]
|
||||
|
||||
def generateBlogTitle(dbConnection: psycopg2.extensions.connection, blogID: int) -> tuple:
|
||||
return dbHandler.changeFieldValueByID(dbConnection, "blogs", blogID, "title", getBlogTitle(blogID))
|
||||
|
||||
def generateBlogDescription(dbConnection: psycopg2.extensions.connection, blogID: int) -> tuple:
|
||||
return dbHandler.changeFieldValueByID(dbConnection, "blogs", blogID, "description", getBlogDescription(blogID))
|
||||
|
||||
def uploadBlog(dbConnection: psycopg2.extensions.connection, userID: int, orgRawIn: str):
|
||||
try:
|
||||
orgParsedOut = orgHandler.orgToHTML(orgRawIn)
|
||||
|
|
@ -43,9 +115,13 @@ def uploadBlog(dbConnection: psycopg2.extensions.connection, userID: int, orgRaw
|
|||
HTMLFileData = open(newBlogDir + "/" + str(blogID) + ".html", 'w')
|
||||
HTMLFileData.write(orgParsedOut)
|
||||
HTMLFileData.close()
|
||||
|
||||
generateBlogTitle(dbConnection, blogID)
|
||||
generateBlogDescription(dbConnection, blogID)
|
||||
|
||||
return blogID
|
||||
else:
|
||||
return False
|
||||
except Exception as error:
|
||||
debugPrint("Create blog failed! " + repr(error))
|
||||
debugPrint("Create blog failed! Unexpected error: " + repr(error) + ".")
|
||||
return False
|
||||
|
|
|
|||
53
dbHandler.py
53
dbHandler.py
|
|
@ -49,9 +49,9 @@ def initTable(dbConnection: psycopg2.extensions.connection, tableName: str, tabl
|
|||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_NAME = '""" + tableName.lower() + """'))
|
||||
THEN
|
||||
RAISE NOTICE '""" + tableName + """ Table does exist! Skipping creating table.';
|
||||
RAISE NOTICE '""" + tableName + """ Table already exists! Skipping table creation...';
|
||||
ELSE
|
||||
RAISE NOTICE '""" + tableName + """ Table does not exist! Creating table.';
|
||||
RAISE NOTICE '""" + tableName + """ Table does not exist! Creating table...';
|
||||
CREATE TABLE """ + tableName.lower() + """ (
|
||||
""" + tableFormat + """
|
||||
);
|
||||
|
|
@ -64,28 +64,34 @@ def initTable(dbConnection: psycopg2.extensions.connection, tableName: str, tabl
|
|||
dbCursor.close()
|
||||
|
||||
# These base functions should not be called directly as they perform no string query sanitisation (Therefore vulnerable to SQL injection attacks)
|
||||
def _commitQuery(dbConnection: psycopg2.extensions.connection, query: sql.Composable) -> list:
|
||||
def _commitQuery(dbConnection: psycopg2.extensions.connection, query: sql.Composable, fetchResults: bool = True):
|
||||
try:
|
||||
debugPrint("Commit query executing...")
|
||||
dbCursor = dbConnection.cursor()
|
||||
dbCursor.execute(query)
|
||||
dbConnection.commit()
|
||||
dbResults = dbCursor.fetchall()
|
||||
dbCursor.close()
|
||||
return dbResults
|
||||
if fetchResults:
|
||||
dbResults = dbCursor.fetchall()
|
||||
dbCursor.close()
|
||||
return dbResults
|
||||
else:
|
||||
return True
|
||||
except Exception as error:
|
||||
errorPrint("Commit query failed! " + repr(error))
|
||||
errorPrint("Commit query failed! Unexpected error: " + repr(error))
|
||||
return None
|
||||
def _execQuery(dbConnection: psycopg2.extensions.connection, query: sql.Composable) -> list:
|
||||
def _execQuery(dbConnection: psycopg2.extensions.connection, query: sql.Composable, fetchResults: bool = True):
|
||||
try:
|
||||
debugPrint("Exec query executing...")
|
||||
dbCursor = dbConnection.cursor()
|
||||
dbCursor.execute(query)
|
||||
dbResults = dbCursor.fetchall()
|
||||
dbCursor.close()
|
||||
return dbResults
|
||||
if fetchResults:
|
||||
dbResults = dbCursor.fetchall()
|
||||
dbCursor.close()
|
||||
return dbResults
|
||||
else:
|
||||
return True
|
||||
except Exception as error:
|
||||
errorPrint("Exec query failed! " + repr(error))
|
||||
errorPrint("Exec query failed! Unexpected error: " + repr(error))
|
||||
return None
|
||||
|
||||
# Callable helper functions
|
||||
|
|
@ -118,6 +124,18 @@ def getFieldValueByID(dbConnection: psycopg2.extensions.connection, tableName: s
|
|||
)
|
||||
return str(_execQuery(dbConnection, sanitisedQuery)[0][0])
|
||||
|
||||
def changeFieldValueByID(dbConnection: psycopg2.extensions.connection, tableName: str, RowID: int, tableField: str, newValue) -> str:
|
||||
debugPrint("Attempting to change value of field name " + tableField + " in ID row " + str(RowID) + " in table name " + tableName + " to " + str(newValue) + "...")
|
||||
sanitisedQuery = sql.SQL("""
|
||||
UPDATE {table} SET {field} = {value} WHERE "id" = {id}
|
||||
""").format(
|
||||
table=sql.Identifier(tableName),
|
||||
field=sql.Identifier(tableField),
|
||||
id=sql.Literal(RowID),
|
||||
value=sql.Literal(newValue)
|
||||
)
|
||||
return _commitQuery(dbConnection, sanitisedQuery, False)
|
||||
|
||||
def getRowByID(dbConnection: psycopg2.extensions.connection, tableName: str, RowID: int) -> tuple:
|
||||
debugPrint("Attempting to get row values by ID " + str(RowID) + " in table name " + tableName + "...")
|
||||
sanitisedQuery = sql.SQL("""
|
||||
|
|
@ -146,3 +164,14 @@ def checkFieldValueExistence(dbConnection: psycopg2.extensions.connection, table
|
|||
)
|
||||
return bool(_execQuery(dbConnection, sanitisedQuery)[0][0])
|
||||
|
||||
def getRowRangeByID(dbConnection: psycopg2.extensions.connection, tableName: str, rangeStart: int, rangeEnd: int, latestRecords = True) -> tuple:
|
||||
debugPrint("Getting rows from table name " + tableName + " from range " + str(rangeStart) + "-" + str(rangeEnd) + "...")
|
||||
sanitisedQuery = sql.SQL("""
|
||||
SELECT * FROM {table} WHERE id >= {start} AND id <= {end} ORDER BY id {order}
|
||||
""").format(
|
||||
table=sql.Identifier(tableName),
|
||||
start=sql.Literal(rangeStart),
|
||||
end=sql.Literal(rangeEnd),
|
||||
order=sql.SQL("DESC" if latestRecords else "ASC")
|
||||
)
|
||||
return tuple(_execQuery(dbConnection, sanitisedQuery))
|
||||
|
|
|
|||
67
main.py
67
main.py
|
|
@ -66,17 +66,19 @@ def apiInit():
|
|||
ID SERIAL PRIMARY KEY,
|
||||
AuthorID INTEGER,
|
||||
CategoryID INTEGER,
|
||||
DatePosted TIMESTAMP
|
||||
DatePosted TIMESTAMP,
|
||||
Title VARCHAR(255),
|
||||
Description VARCHAR(255)
|
||||
""")
|
||||
dbHandler.initTable(dbConnection, "Categories", """
|
||||
ID SERIAL PRIMARY KEY,
|
||||
Name VARCHAR(255)
|
||||
""")
|
||||
debugInitPrint("Creating blog data directory at " + blogDir + "...")
|
||||
if not os.path.exists(blogDir):
|
||||
debugInitPrint("Blog data directory does not exist! Creating blog data directory at " + blogDir + "...")
|
||||
os.mkdir(blogDir)
|
||||
else:
|
||||
debugInitPrint("Blog data directory already exists! Skipping...")
|
||||
debugInitPrint("Blog data directory already exists! Skipping directory creation...")
|
||||
# userHandler.createUser(dbConnection, "testuser", "Test", "User", "A test user", "TestCountry", "TestTheme", "TestColor", "testuser")
|
||||
|
||||
def apiCleanup():
|
||||
|
|
@ -115,8 +117,8 @@ class ApiBody(BaseModel):
|
|||
password: str
|
||||
@app.post("/api")
|
||||
def postapi(body: ApiBody):
|
||||
print(body.username)
|
||||
print(body.password)
|
||||
debugPrint(body.username)
|
||||
debugPrint(body.password)
|
||||
return body
|
||||
|
||||
class postuserLoginBody(BaseModel):
|
||||
|
|
@ -136,7 +138,7 @@ def postuserLogin(body: postuserLoginBody, request: Request):
|
|||
return {"success": False, "authToken": None, "message": "User login failed! User does not exist."}
|
||||
except Exception as error:
|
||||
msg = "User login failed! Unexpected server error. " + repr(error)
|
||||
print(msg)
|
||||
debugPrint(msg)
|
||||
return {"success": False, "authToken": None, "message": msg}
|
||||
|
||||
@app.get("/api/user/IDByAuthToken")
|
||||
|
|
@ -149,7 +151,7 @@ def getuserIDByAuthToken(authToken: Annotated[str | None, Header()] = None):
|
|||
return {"success": False, "userID": None, "message": "Get userID by authToken failed! authToken provided is not valid."}
|
||||
except Exception as error:
|
||||
msg = "Get userID by authToken failed! Unexpected server error. " + repr(error)
|
||||
print(msg)
|
||||
debugPrint(msg)
|
||||
return {"success": False, "authToken": None, "message": msg}
|
||||
|
||||
@app.get("/api/user/publicInfo/{userID}")
|
||||
|
|
@ -173,7 +175,7 @@ def getuserPublicInfo(userID: int):
|
|||
}
|
||||
except Exception as error:
|
||||
msg = "Get public info failed! Unexpected server error. " + repr(error)
|
||||
print(msg)
|
||||
debugPrint(msg)
|
||||
return {
|
||||
"success": False,
|
||||
"username": None,
|
||||
|
|
@ -204,7 +206,7 @@ def getuserSettingsAccount(authToken: Annotated[str | None, Header()] = None):
|
|||
}
|
||||
except Exception as error:
|
||||
msg = "Get user settings failed! Unexpected server error. " + repr(error)
|
||||
print(msg)
|
||||
debugPrint(msg)
|
||||
return {
|
||||
"success": False,
|
||||
"username": None,
|
||||
|
|
@ -213,6 +215,49 @@ def getuserSettingsAccount(authToken: Annotated[str | None, Header()] = None):
|
|||
"message": msg
|
||||
}
|
||||
|
||||
@app.get("/api/user/blog/cardInfo/")
|
||||
def getblogCardInfo(rangeStart: int = 1, rangeEnd: int = 25, sortByLatest: bool = True):
|
||||
try:
|
||||
blogCardData = blogHandler.getBlogCardRange(dbConnection, rangeStart, rangeEnd, sortByLatest)
|
||||
blogCardData[0] = {
|
||||
"success": True,
|
||||
"message": "Get card info succeeded!"
|
||||
}
|
||||
return blogCardData
|
||||
except Exception as error:
|
||||
blogCardData = {}
|
||||
msg = "Get card info failed! Unexpected server error. " + repr(error)
|
||||
debugPrint(msg)
|
||||
blogCardData[0] = {
|
||||
"success": False,
|
||||
"message": msg
|
||||
}
|
||||
return blogCardData
|
||||
|
||||
@app.get("/api/blog/contents/HTML/{blogID}")
|
||||
def getblogContentsHTML(blogID: int):
|
||||
try:
|
||||
if blogHandler.checkIDExistence(dbConnection, blogID):
|
||||
return {
|
||||
"success": True,
|
||||
"contents": blogHandler.getBlogContentsHTML(blogID),
|
||||
"message": "Get blog contents in HTML succeeded!"
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"contents": None,
|
||||
"message": "Get blog contents in HTML failed! BlogID provided does not exist."
|
||||
}
|
||||
except Exception as error:
|
||||
msg = "Get blog contents in HTML failed! Unexpected server error. " + repr(error)
|
||||
debugPrint(msg)
|
||||
return {
|
||||
"success": False,
|
||||
"contents": None,
|
||||
"message": msg
|
||||
}
|
||||
|
||||
|
||||
class postblogCreateBody(BaseModel):
|
||||
authToken: str
|
||||
|
|
@ -243,7 +288,7 @@ def postblogCreate(body: postblogCreateBody):
|
|||
}
|
||||
except Exception as error:
|
||||
msg = "Create blog failed! Unexpected server error. " + repr(error)
|
||||
print(msg)
|
||||
debugPrint(msg)
|
||||
return {
|
||||
"success": False,
|
||||
"blogID": None,
|
||||
|
|
@ -275,6 +320,8 @@ def postblogCreate(body: postblogCreateBody):
|
|||
# /api/blog/pictureURL/{blogID}
|
||||
# /api/blog/description/{blogID}
|
||||
# /api/blog/datePosted/{blogID}
|
||||
# /api/blog/contents/HTML/{blogID}
|
||||
# /api/blog/contents/org/{blogID}
|
||||
|
||||
# POST
|
||||
# /api/user/changeInfo/{infotype}
|
||||
|
|
|
|||
|
|
@ -16,32 +16,7 @@ def checkAndRetrieveMetadata(fileData: str, metadataName: str):
|
|||
else:
|
||||
debugPrint("Could not find " + metadataFullName + " metadata field of document!")
|
||||
return False
|
||||
|
||||
def getOrgTitle(blogID: int) -> str:
|
||||
try:
|
||||
fileData = open(blogDir + "/" + str(blogID) + "/" + str(blogID) + ".org", 'r')
|
||||
title = checkAndRetrieveMetadata(fileData, "TITLE")
|
||||
if title:
|
||||
return title
|
||||
except Exception as error:
|
||||
debugPrint("Error getting blog title! " + repr(error))
|
||||
|
||||
def getOrgDescription(blogID: str) -> str:
|
||||
try:
|
||||
fileData = open(blogDir + "/" + str(blogID) + "/" + str(blogID) + ".org", 'r')
|
||||
orgRoot = loads(fileData.read())
|
||||
|
||||
fileData.readline()
|
||||
shortDescription = checkAndRetrieveMetadata(fileData, "DESCRIPTION")
|
||||
if not shortDescription:
|
||||
debugPrint("No valid description found, will generate a placeholder from the text itself...")
|
||||
firstText = orgRoot[1].body
|
||||
shortDescription = (firstText[:60] + "...") if len(firstText) > 60 else firstText
|
||||
return shortDescription
|
||||
except Exception as error:
|
||||
debugPrint("Error getting org title! " + repr(error))
|
||||
|
||||
|
||||
def orgToHTML(orgData: str) -> str:
|
||||
try:
|
||||
orgRoot = loads(orgData)
|
||||
|
|
@ -49,10 +24,10 @@ def orgToHTML(orgData: str) -> str:
|
|||
|
||||
for node in orgRoot[1:]:
|
||||
if node.heading:
|
||||
headingLevel = str(node.level)
|
||||
headingLevel = str(node.level if node.level <= 6 else 6)
|
||||
parsedHTML += "<h" + headingLevel + ">" + node.heading + "</h" + headingLevel + ">" + "\n"
|
||||
if node.body:
|
||||
parsedHTML += node.body + "\n"
|
||||
return parsedHTML
|
||||
except Exception as error:
|
||||
debugPrint("Error parsing org! " + repr(error))
|
||||
debugPrint("Error parsing org! Unexpected error: " + repr(error) + ".")
|
||||
|
|
|
|||
|
|
@ -35,14 +35,18 @@ def verifyRehash(hash: str) -> bool:
|
|||
return False
|
||||
|
||||
def handlePasswordVerification(dbConnection: psycopg2.extensions.connection, password: str, userID: int) -> bool:
|
||||
hash = userHandler.getHashValueByUserID(dbConnection, userID)
|
||||
userIDstr = str(userID)
|
||||
debugPrint("Now verifying password against hash for user ID " + userIDstr + "...")
|
||||
if verifyPassword(password, hash):
|
||||
debugPrint("(USER ID " + userIDstr + ") Password verification success!")
|
||||
if verifyRehash(hash):
|
||||
debugPrint("(USER ID " + userIDstr + ") Hash needs to be rehashed! Will now rehash...")
|
||||
return True
|
||||
else:
|
||||
debugPrint("(USER ID " + userIDstr + ") Password verification failure!")
|
||||
try:
|
||||
hash = userHandler.getHashValueByUserID(dbConnection, userID)
|
||||
userIDstr = str(userID)
|
||||
debugPrint("Now verifying password against hash for user ID " + userIDstr + "...")
|
||||
if verifyPassword(password, hash):
|
||||
debugPrint("(USER ID " + userIDstr + ") Password verification success!")
|
||||
if verifyRehash(hash):
|
||||
debugPrint("(USER ID " + userIDstr + ") Hash needs to be rehashed! Will now rehash...")
|
||||
return True
|
||||
else:
|
||||
debugPrint("(USER ID " + userIDstr + ") Password verification failure! Invalid password.")
|
||||
return False
|
||||
except Exception as error:
|
||||
debugPrint("(USER ID " + userIDstr + ") Password verification failure! Unexpected error: " + repr(error) + ".")
|
||||
return False
|
||||
|
|
|
|||
Loading…
Reference in New Issue