Loading tornado-backend/blog.py +81 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import logging # Configure logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') from datetime import datetime, date from tornado.options import define, options Loading Loading @@ -77,6 +78,8 @@ class Application(tornado.web.Application): (r"/tornado-backend/login", AuthorLoginHandler), (r"/tornado-backend/logout", AuthLogoutHandler), (r"/tornado-backend/get-user-role", GetUserRoleHandler), (r"/tornado-backend/blog-entries", BlogEntriesHandler), (r"/tornado-backend/create-blog-entry", CreateBlogEntryHandler), ] settings = dict( blog_title="Tornado Blog", Loading Loading @@ -154,6 +157,12 @@ class BaseHandler(tornado.web.RequestHandler): async def any_author_exists(self): return bool(await self.query("SELECT * FROM authors LIMIT 1")) # Serialization of dates def date_serialization(self, obj): if isinstance(obj, (date, datetime)): return obj.isoformat() raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable") class HomeHandler(BaseHandler): async def get(self): Loading Loading @@ -400,6 +409,78 @@ class GetUserRoleHandler(BaseHandler): return class BlogEntriesHandler(BaseHandler): async def get(self): try: # Query to fetch all entries, ordered by published date entries = await self.query("SELECT * FROM entries ORDER BY published DESC") logging.info(f"logging of entries: {entries}") # Format the entries as a JSON response # self.write({"status": "success", "data": entries}) self.write(json.dumps({"status": "success", "data": entries }, default=self.date_serialization)) except Exception as e: logging.error(f"Error fetching blog entries: {e}") self.set_status(500) self.write({"status": "error", "message": "Failed to fetch blog entries"}) class CreateBlogEntryHandler(BaseHandler): @tornado.web.authenticated async def post(self): logging.info(f"Data arriving at CreateBlogEntryHandler {self.request.body}") try: # Parse JSON data from the request body data = json.loads(self.request.body) logging.info(f"Data arriving at CreateBlogEntryHandler {data}") title = data.get("title") text = data.get("markdown") if not title or not text: raise tornado.web.HTTPError(400, "Title and markdown are required") # Convert markdown to HTML html = markdown.markdown(text) # Generate a unique slug from the title slug = unicodedata.normalize("NFKD", title) slug = re.sub(r"[^\w]+", "-", slug) slug = slug.strip("-").lower() slug = slug.encode("ascii", "ignore").decode("ascii") if not slug: slug = "entry" # Ensure slug uniqueness while True: existing = await self.query("SELECT * FROM entries WHERE slug = %s", slug) if not existing: break slug += "-2" # Insert the new entry into the database await self.execute( "INSERT INTO entries (author_id, title, slug, markdown, html, published, updated) " "VALUES (%s, %s, %s, %s, %s, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)", self.current_user.id, title, slug, text, html, ) # Respond with success self.write({"status": "success", "message": "Blog post created", "slug": slug}) except Exception as e: logging.error(f"Error creating blog post: {e}") self.set_status(500) self.write({"status": "error", "message": "Failed to create blog post"}) async def main(): tornado.options.parse_command_line() Loading Loading
tornado-backend/blog.py +81 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import logging # Configure logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') from datetime import datetime, date from tornado.options import define, options Loading Loading @@ -77,6 +78,8 @@ class Application(tornado.web.Application): (r"/tornado-backend/login", AuthorLoginHandler), (r"/tornado-backend/logout", AuthLogoutHandler), (r"/tornado-backend/get-user-role", GetUserRoleHandler), (r"/tornado-backend/blog-entries", BlogEntriesHandler), (r"/tornado-backend/create-blog-entry", CreateBlogEntryHandler), ] settings = dict( blog_title="Tornado Blog", Loading Loading @@ -154,6 +157,12 @@ class BaseHandler(tornado.web.RequestHandler): async def any_author_exists(self): return bool(await self.query("SELECT * FROM authors LIMIT 1")) # Serialization of dates def date_serialization(self, obj): if isinstance(obj, (date, datetime)): return obj.isoformat() raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable") class HomeHandler(BaseHandler): async def get(self): Loading Loading @@ -400,6 +409,78 @@ class GetUserRoleHandler(BaseHandler): return class BlogEntriesHandler(BaseHandler): async def get(self): try: # Query to fetch all entries, ordered by published date entries = await self.query("SELECT * FROM entries ORDER BY published DESC") logging.info(f"logging of entries: {entries}") # Format the entries as a JSON response # self.write({"status": "success", "data": entries}) self.write(json.dumps({"status": "success", "data": entries }, default=self.date_serialization)) except Exception as e: logging.error(f"Error fetching blog entries: {e}") self.set_status(500) self.write({"status": "error", "message": "Failed to fetch blog entries"}) class CreateBlogEntryHandler(BaseHandler): @tornado.web.authenticated async def post(self): logging.info(f"Data arriving at CreateBlogEntryHandler {self.request.body}") try: # Parse JSON data from the request body data = json.loads(self.request.body) logging.info(f"Data arriving at CreateBlogEntryHandler {data}") title = data.get("title") text = data.get("markdown") if not title or not text: raise tornado.web.HTTPError(400, "Title and markdown are required") # Convert markdown to HTML html = markdown.markdown(text) # Generate a unique slug from the title slug = unicodedata.normalize("NFKD", title) slug = re.sub(r"[^\w]+", "-", slug) slug = slug.strip("-").lower() slug = slug.encode("ascii", "ignore").decode("ascii") if not slug: slug = "entry" # Ensure slug uniqueness while True: existing = await self.query("SELECT * FROM entries WHERE slug = %s", slug) if not existing: break slug += "-2" # Insert the new entry into the database await self.execute( "INSERT INTO entries (author_id, title, slug, markdown, html, published, updated) " "VALUES (%s, %s, %s, %s, %s, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)", self.current_user.id, title, slug, text, html, ) # Respond with success self.write({"status": "success", "message": "Blog post created", "slug": slug}) except Exception as e: logging.error(f"Error creating blog post: {e}") self.set_status(500) self.write({"status": "error", "message": "Failed to create blog post"}) async def main(): tornado.options.parse_command_line() Loading