Skip to content

Commit 05838cb

Browse files
55 - Public Articles Display
1 parent 94afd16 commit 05838cb

File tree

8 files changed

+168
-0
lines changed

8 files changed

+168
-0
lines changed

full_stack_python/articles/__init__.py

Whitespace-only changes.

full_stack_python/articles/detail.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import reflex as rx
2+
3+
from ..ui.base import base_page
4+
5+
from . import state
6+
7+
from ..blog.notfound import blog_post_not_found
8+
9+
10+
def article_detail_page() -> rx.Component:
11+
my_child = rx.cond(state.ArticlePublicState.post, rx.vstack(
12+
rx.hstack(
13+
rx.heading(state.ArticlePublicState.post.title, size="9"),
14+
align='end'
15+
),
16+
rx.text("By ", state.ArticlePublicState.post.userinfo.user.username),
17+
rx.text(state.ArticlePublicState.post.publish_date),
18+
rx.text(
19+
state.ArticlePublicState.post.content,
20+
white_space='pre-wrap'
21+
),
22+
spacing="5",
23+
align="center",
24+
min_height="85vh"
25+
),
26+
blog_post_not_found()
27+
)
28+
return base_page(my_child)

full_stack_python/articles/list.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import reflex as rx
2+
3+
from .. import navigation
4+
from ..ui.base import base_page
5+
from ..models import BlogPostModel
6+
from . import state
7+
8+
def article_link(post: BlogPostModel):
9+
post_id = post.id
10+
if post_id is None:
11+
return rx.fragment("Not found")
12+
root_path = navigation.routes.ARTICLE_LIST_ROUTE
13+
post_detail_url = f"{root_path}/{post_id}"
14+
return rx.card(
15+
rx.link(
16+
rx.flex(
17+
rx.box(
18+
rx.heading(post.title),
19+
),
20+
spacing="2",
21+
),
22+
href=post_detail_url
23+
),
24+
as_child=True,
25+
)
26+
27+
def article_list_item(post: BlogPostModel):
28+
return rx.box(
29+
article_link(post),
30+
padding='1em'
31+
)
32+
33+
34+
def article_public_list_page() ->rx.Component:
35+
return base_page(
36+
rx.vstack(
37+
rx.heading("Published Articles", size="5"),
38+
rx.foreach(state.ArticlePublicState.posts, article_list_item),
39+
spacing="5",
40+
align="center",
41+
min_height="85vh",
42+
)
43+
)

full_stack_python/articles/state.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from datetime import datetime
2+
from typing import Optional, List
3+
import reflex as rx
4+
5+
import sqlalchemy
6+
from sqlmodel import select
7+
8+
from .. import navigation
9+
from ..auth.state import SessionState
10+
from ..models import BlogPostModel, UserInfo
11+
12+
ARTICLE_LIST_ROUTE = navigation.routes.ARTICLE_LIST_ROUTE
13+
if ARTICLE_LIST_ROUTE.endswith("/"):
14+
ARTICLE_LIST_ROUTE = ARTICLE_LIST_ROUTE[:-1]
15+
16+
class ArticlePublicState(SessionState):
17+
posts: List['BlogPostModel'] = []
18+
post: Optional['BlogPostModel'] = None
19+
post_content: str = ""
20+
post_publish_active: bool = False
21+
22+
@rx.var
23+
def post_id(self):
24+
return self.router.page.params.get("post_id", "")
25+
26+
@rx.var
27+
def post_url(self):
28+
if not self.post:
29+
return f"{ARTICLE_LIST_ROUTE}"
30+
return f"{ARTICLE_LIST_ROUTE}/{self.post.id}"
31+
32+
def get_post_detail(self):
33+
lookups = (
34+
(BlogPostModel.publish_active == True) &
35+
(BlogPostModel.publish_date < datetime.now()) &
36+
(BlogPostModel.id == self.post_id)
37+
)
38+
with rx.session() as session:
39+
if self.post_id == "":
40+
self.post = None
41+
self.post_content = ""
42+
self.post_publish_active = False
43+
return
44+
sql_statement = select(BlogPostModel).options(
45+
sqlalchemy.orm.joinedload(BlogPostModel.userinfo).joinedload(UserInfo.user)
46+
).where(lookups)
47+
result = session.exec(sql_statement).one_or_none()
48+
self.post = result
49+
if result is None:
50+
self.post_content = ""
51+
return
52+
self.post_content = self.post.content
53+
self.post_publish_active = self.post.publish_active
54+
# return
55+
56+
def load_posts(self, *args, **kwargs):
57+
lookup_args = (
58+
(BlogPostModel.publish_active == True) &
59+
(BlogPostModel.publish_date < datetime.now())
60+
)
61+
with rx.session() as session:
62+
result = session.exec(
63+
select(BlogPostModel).options(
64+
sqlalchemy.orm.joinedload(BlogPostModel.userinfo)
65+
).where(lookup_args)
66+
).all()
67+
self.posts = result
68+
69+
def to_post(self):
70+
if not self.post:
71+
return rx.redirect(ARTICLE_LIST_ROUTE)
72+
return rx.redirect(f"{self.post_url}")

full_stack_python/full_stack_python.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
)
1414
from .auth.state import SessionState
1515

16+
17+
from .articles.detail import article_detail_page
18+
from .articles.list import article_public_list_page
19+
from .articles.state import ArticlePublicState
20+
1621
from . import blog, contact, navigation, pages
1722

1823
class State(rx.State):
@@ -85,6 +90,20 @@ def index() -> rx.Component:
8590
on_load=SessionState.on_load
8691
)
8792

93+
94+
app.add_page(
95+
article_public_list_page,
96+
route=navigation.routes.ARTICLE_LIST_ROUTE,
97+
on_load=ArticlePublicState.load_posts
98+
)
99+
100+
app.add_page(
101+
article_detail_page,
102+
route=f"{navigation.routes.ARTICLE_LIST_ROUTE}/[post_id]",
103+
on_load=ArticlePublicState.get_post_detail
104+
)
105+
106+
88107
app.add_page(
89108
blog.blog_post_list_page,
90109
route=navigation.routes.BLOG_POSTS_ROUTE,

full_stack_python/navigation/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
HOME_ROUTE="/"
22
ABOUT_US_ROUTE="/about"
3+
ARTICLE_LIST_ROUTE="/articles"
34
BLOG_POSTS_ROUTE="/blog"
45
BLOG_POST_ADD_ROUTE="/blog/add"
56
CONTACT_US_ROUTE="/contact"

full_stack_python/navigation/state.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def to_logout(self):
1717

1818
def to_about_us(self):
1919
return rx.redirect(routes.ABOUT_US_ROUTE)
20+
21+
def to_articles(self):
22+
return rx.redirect(routes.ARTICLE_LIST_ROUTE)
23+
2024
def to_blog(self):
2125
return rx.redirect(routes.BLOG_POSTS_ROUTE)
2226
def to_blog_add(self):

full_stack_python/ui/sidebar.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ def sidebar_item(
130130
def sidebar_items() -> rx.Component:
131131
return rx.vstack(
132132
sidebar_item("Dashboard", "layout-dashboard", navigation.routes.HOME_ROUTE),
133+
sidebar_item("Articles", "globe", navigation.routes.ARTICLE_LIST_ROUTE),
133134
sidebar_item("Blog", "newspaper", navigation.routes.BLOG_POSTS_ROUTE),
134135
sidebar_item("Create post", "notebook-pen", navigation.routes.BLOG_POST_ADD_ROUTE),
135136
sidebar_item("Contact", "mail", navigation.routes.CONTACT_US_ROUTE),

0 commit comments

Comments
 (0)