Author | zPlus <zplus@peers.community> 2018-07-22 07:43:39 |
Committer | zPlus <zplus@peers.community> 2018-07-22 07:43:39 |
Commit | 022590a (patch) |
Tree | ff60fdb |
Parent(s) |
-rwxr-xr-x | freepost/__init__.py | 81 | ||
-rw-r--r-- | freepost/database.py | 45 | ||
-rwxr-xr-x | freepost/static/stylus/freepost.styl | 17 | ||
-rwxr-xr-x | freepost/static/stylus/reset.styl | 8 | ||
-rwxr-xr-x | freepost/templates/homepage.html | 4 | ||
-rw-r--r-- | freepost/templates/layout.html | 74 | ||
-rwxr-xr-x | freepost/templates/submit.html | 2 | ||
-rwxr-xr-x | freepost/templates/user_settings.html | 0 |
index e76844a..060df8c | |||
old size: 25K - new size: 25K | |||
@@ -49,13 +49,14 @@ template = functools.partial ( | |||
49 | 49 | 'globals': { | |
50 | 50 | 'new_messages': lambda user_id: database.count_unread_messages (user_id), | |
51 | 51 | 'now': lambda: datetime.now (timezone.utc), | |
52 | - | 'url': application.get_url, | |
52 | + | 'request': request, | |
53 | 53 | # Return a setting from 'settings.yaml' | |
54 | 54 | 'settings': lambda section, key: settings[section][key], | |
55 | 55 | # Get the current user of the session | |
56 | 56 | 'session_user': lambda: session.user (), | |
57 | 57 | # Split a string of topics into a list | |
58 | - | 'split_topics': lambda topics: [ topic for topic in topics.split (' ') ] if topics else [] | |
58 | + | 'split_topics': lambda topics: [ topic for topic in topics.split (' ') ] if topics else [], | |
59 | + | 'url': application.get_url, | |
59 | 60 | }, | |
60 | 61 | 'autoescape': True | |
61 | 62 | }) | |
@@ -94,7 +95,7 @@ def requires_logout (controller): | |||
94 | 95 | secret = settings['cookies']['secret']) | |
95 | 96 | ||
96 | 97 | if database.is_valid_session (session_token): | |
97 | - | redirect (application.get_url ('user')) | |
98 | + | redirect (application.get_url ('user_settings')) | |
98 | 99 | else: | |
99 | 100 | return controller () | |
100 | 101 | ||
@@ -108,26 +109,8 @@ def homepage (): | |||
108 | 109 | Display homepage with posts sorted by 'hot'. | |
109 | 110 | """ | |
110 | 111 | ||
111 | - | # Page number | |
112 | - | page = int (request.query.page or 0) | |
113 | - | ||
114 | - | if page < 0: | |
115 | - | redirect (application.get_url ('homepage')) | |
116 | - | ||
117 | - | user = session.user () | |
118 | - | posts = database.get_hot_posts (page, user['id'] if user else None) | |
119 | - | ||
120 | - | return template ( | |
121 | - | 'homepage.html', | |
122 | - | page_number=page, | |
123 | - | posts=posts, | |
124 | - | sorting='hot') | |
125 | - | ||
126 | - | @get ('/new', name='new') | |
127 | - | def new (): | |
128 | - | """ | |
129 | - | Display homepage with posts sorted by 'new'. | |
130 | - | """ | |
112 | + | # Sort order | |
113 | + | sort = request.query.sort or 'hot' | |
131 | 114 | ||
132 | 115 | # Page number | |
133 | 116 | page = int (request.query.page or 0) | |
@@ -136,13 +119,19 @@ def new (): | |||
136 | 119 | redirect (application.get_url ('homepage')) | |
137 | 120 | ||
138 | 121 | user = session.user () | |
139 | - | posts = database.get_new_posts (page, user['id'] if user else None) | |
122 | + | ||
123 | + | if sort in [ 'hot', 'new' ]: | |
124 | + | posts = database.get_posts ( | |
125 | + | page, user['id'] if user else None, | |
126 | + | sort) | |
127 | + | else: | |
128 | + | posts = [] | |
140 | 129 | ||
141 | 130 | return template ( | |
142 | 131 | 'homepage.html', | |
143 | 132 | page_number=page, | |
144 | 133 | posts=posts, | |
145 | - | sorting='new') | |
134 | + | sorting=sort) | |
146 | 135 | ||
147 | 136 | # TODO implement this | |
148 | 137 | @get ('/topic/<name>', name='topic') | |
@@ -151,22 +140,30 @@ def topic (name): | |||
151 | 140 | Display posts by topic. | |
152 | 141 | """ | |
153 | 142 | ||
154 | - | return "" | |
143 | + | # Sort order | |
144 | + | sort = request.query.sort or 'hot' | |
155 | 145 | ||
156 | 146 | # Page number | |
157 | 147 | page = int (request.query.page or 0) | |
158 | 148 | ||
159 | 149 | if page < 0: | |
160 | - | redirect (application.get_url ('topic', name=name)) | |
150 | + | redirect (application.get_url ('homepage')) | |
161 | 151 | ||
162 | 152 | user = session.user () | |
163 | - | posts = database.get_topic_posts (page, user['id'] if user else None) | |
153 | + | ||
154 | + | if sort in [ 'hot', 'new' ]: | |
155 | + | posts = database.get_posts ( | |
156 | + | page, user['id'] if user else None, | |
157 | + | sort, name) | |
158 | + | else: | |
159 | + | posts = [] | |
164 | 160 | ||
165 | 161 | return template ( | |
166 | 162 | 'homepage.html', | |
163 | + | topic=name, | |
167 | 164 | page_number=page, | |
168 | 165 | posts=posts, | |
169 | - | sorting='hot') | |
166 | + | sorting=sort) | |
170 | 167 | ||
171 | 168 | @get ('/about', name='about') | |
172 | 169 | def about (): | |
@@ -393,20 +390,20 @@ def validate_new_password (): | |||
393 | 390 | ||
394 | 391 | # Start new session and redirect user | |
395 | 392 | session.start (user['id']) | |
396 | - | redirect (application.get_url ('user')) | |
393 | + | redirect (application.get_url ('user_settings')) | |
397 | 394 | ||
398 | - | @get ('/user', name='user') | |
395 | + | @get ('/user/settings', name='user_settings') | |
399 | 396 | @requires_login | |
400 | - | def user_private_homepage (): | |
397 | + | def user_settings (): | |
401 | 398 | """ | |
402 | 399 | A user's personal page. | |
403 | 400 | """ | |
404 | 401 | ||
405 | - | return template ('user_private_homepage.html') | |
402 | + | return template ('user_settings.html') | |
406 | 403 | ||
407 | - | @post ('/user') | |
404 | + | @post ('/user/settings') | |
408 | 405 | @requires_login | |
409 | - | def update_user (): | |
406 | + | def update_user_settings (): | |
410 | 407 | """ | |
411 | 408 | Update user info (about, email, ...). | |
412 | 409 | """ | |
@@ -417,12 +414,12 @@ def update_user (): | |||
417 | 414 | email = request.forms.get ('email') | |
418 | 415 | ||
419 | 416 | if about is None or email is None: | |
420 | - | redirect (application.get_url ('user')) | |
417 | + | redirect (application.get_url ('user_settings')) | |
421 | 418 | ||
422 | 419 | # Update user info in the database | |
423 | 420 | database.update_user (user['id'], about, email, False) | |
424 | 421 | ||
425 | - | redirect (application.get_url ('user')) | |
422 | + | redirect (application.get_url ('user_settings')) | |
426 | 423 | ||
427 | 424 | @get ('/user_activity/posts') | |
428 | 425 | @requires_login | |
@@ -440,7 +437,7 @@ def user_comments (): | |||
440 | 437 | ||
441 | 438 | return template ('user_comments.html', comments=comments) | |
442 | 439 | ||
443 | - | @get ('/user_activity/replies') | |
440 | + | @get ('/user_activity/replies', name='user_replies') | |
444 | 441 | @requires_login | |
445 | 442 | def user_replies (): | |
446 | 443 | user = session.user () | |
@@ -450,7 +447,7 @@ def user_replies (): | |||
450 | 447 | ||
451 | 448 | return template ('user_replies.html', replies=replies) | |
452 | 449 | ||
453 | - | @get ('/user/<username>', name='user_public') | |
450 | + | @get ('/user/public/<username>', name='user_public') | |
454 | 451 | def user_public_homepage (username): | |
455 | 452 | """ | |
456 | 453 | Display a publicly accessible page with public info about the user. | |
@@ -459,7 +456,7 @@ def user_public_homepage (username): | |||
459 | 456 | account = database.get_user_by_username (username) | |
460 | 457 | ||
461 | 458 | if account is None: | |
462 | - | redirect (application.get_url ('user')) | |
459 | + | redirect (application.get_url ('user_settings')) | |
463 | 460 | ||
464 | 461 | return template ('user_public_homepage.html', account=account) | |
465 | 462 | ||
@@ -610,7 +607,7 @@ def submit (): | |||
610 | 607 | ||
611 | 608 | return template ('submit.html') | |
612 | 609 | ||
613 | - | @post ('/submit') | |
610 | + | @post ('/submit', name='submit') | |
614 | 611 | @requires_login | |
615 | 612 | def submit_check (): | |
616 | 613 | """ | |
@@ -783,7 +780,7 @@ def vote (): | |||
783 | 780 | # Add -1 | |
784 | 781 | database.vote_comment (comment['id'], user['id'], -1) | |
785 | 782 | ||
786 | - | @get ('/search') | |
783 | + | @get ('/search', name='search') | |
787 | 784 | def search (): | |
788 | 785 | """ | |
789 | 786 | Search content on this instance, and display the results. |
index bedc247..f81d8ea | |||
old size: 18K - new size: 18K | |||
@@ -157,36 +157,17 @@ def get_user_by_session_token (session_token): | |||
157 | 157 | return cursor.fetchone () | |
158 | 158 | ||
159 | 159 | # Get posts by date (for homepage) | |
160 | - | def get_new_posts (page = 0, session_user_id = None): | |
161 | - | cursor = db.cursor (MySQLdb.cursors.DictCursor) | |
160 | + | def get_posts (page = 0, session_user_id = None, sort = 'hot', topic = None): | |
161 | + | if sort == 'new': | |
162 | + | sort = 'ORDER BY P.created DESC' | |
163 | + | else: | |
164 | + | sort = 'ORDER BY P.dateCreated DESC, P.vote DESC, P.commentsCount DESC' | |
162 | 165 | ||
163 | - | cursor.execute ( | |
164 | - | """ | |
165 | - | SELECT | |
166 | - | P.*, | |
167 | - | U.username, | |
168 | - | V.vote AS user_vote, | |
169 | - | GROUP_CONCAT(DISTINCT T.name ORDER BY T.name SEPARATOR " ") AS topics | |
170 | - | FROM post AS P | |
171 | - | JOIN user AS U ON P.userId = U.id | |
172 | - | LEFT JOIN vote_post as V ON V.postId = P.id AND V.userId = %(user)s | |
173 | - | LEFT JOIN topic as T ON T.post_id = P.id | |
174 | - | GROUP BY P.id | |
175 | - | ORDER BY P.created DESC | |
176 | - | LIMIT %(limit)s | |
177 | - | OFFSET %(offset)s | |
178 | - | """, | |
179 | - | { | |
180 | - | 'user': session_user_id, | |
181 | - | 'limit': settings['defaults']['items_per_page'], | |
182 | - | 'offset': page * settings['defaults']['items_per_page'] | |
183 | - | } | |
184 | - | ) | |
166 | + | if topic: | |
167 | + | topic_name = 'WHERE T.name = %(topic)s' | |
168 | + | else: | |
169 | + | topic_name = '' | |
185 | 170 | ||
186 | - | return cursor.fetchall () | |
187 | - | ||
188 | - | # Get posts by rating (for homepage) | |
189 | - | def get_hot_posts (page = 0, session_user_id = None): | |
190 | 171 | cursor = db.cursor (MySQLdb.cursors.DictCursor) | |
191 | 172 | ||
192 | 173 | cursor.execute ( | |
@@ -200,15 +181,17 @@ def get_hot_posts (page = 0, session_user_id = None): | |||
200 | 181 | JOIN user AS U ON P.userId = U.id | |
201 | 182 | LEFT JOIN vote_post as V ON V.postId = P.id AND V.userId = %(user)s | |
202 | 183 | LEFT JOIN topic as T ON T.post_id = P.id | |
184 | + | {topic} | |
203 | 185 | GROUP BY P.id | |
204 | - | ORDER BY P.dateCreated DESC, P.vote DESC, P.commentsCount DESC | |
186 | + | {order} | |
205 | 187 | LIMIT %(limit)s | |
206 | 188 | OFFSET %(offset)s | |
207 | - | """, | |
189 | + | """.format (topic=topic_name, order=sort), | |
208 | 190 | { | |
209 | 191 | 'user': session_user_id, | |
210 | 192 | 'limit': settings['defaults']['items_per_page'], | |
211 | - | 'offset': page * settings['defaults']['items_per_page'] | |
193 | + | 'offset': page * settings['defaults']['items_per_page'], | |
194 | + | 'topic': topic | |
212 | 195 | } | |
213 | 196 | ) | |
214 | 197 |
index c80a570..b60b12e | |||
old size: 11K - new size: 11K | |||
@@ -40,11 +40,13 @@ body | |||
40 | 40 | ||
41 | 41 | /* Page header */ | |
42 | 42 | > .header | |
43 | + | display grid | |
44 | + | grid-template-columns max-content auto | |
43 | 45 | padding 1rem 0 | |
44 | 46 | text-align center | |
45 | 47 | ||
46 | 48 | /* Menu under the logo */ | |
47 | - | > .menu | |
49 | + | .menu | |
48 | 50 | border-bottom 1px solid transparent | |
49 | 51 | display flex | |
50 | 52 | flex-direction row | |
@@ -53,8 +55,6 @@ body | |||
53 | 55 | align-content flex-start | |
54 | 56 | align-items flex-start | |
55 | 57 | ||
56 | - | margin 1em auto | |
57 | - | ||
58 | 58 | > .flex-item | |
59 | 59 | flex 0 1 auto | |
60 | 60 | align-self auto | |
@@ -65,10 +65,6 @@ body | |||
65 | 65 | color #000 | |
66 | 66 | margin 0 0 | |
67 | 67 | padding 0 .5rem .5rem .5rem | |
68 | - | ||
69 | - | &:first-child | |
70 | - | border-bottom 2px solid transparent | |
71 | - | margin-left 0 | |
72 | 68 | ||
73 | 69 | /* Highlight menu item of the current active page (Hot/New/Submit/...) */ | |
74 | 70 | > .active_page | |
@@ -84,6 +80,13 @@ body | |||
84 | 80 | padding .5em .5em | |
85 | 81 | text-decoration none | |
86 | 82 | ||
83 | + | .submenu | |
84 | + | display flex | |
85 | + | flex-direction row | |
86 | + | flex-wrap wrap | |
87 | + | justify-content flex-start | |
88 | + | align-content flex-start | |
89 | + | align-items flex-start | |
87 | 90 | ||
88 | 91 | > .content | |
89 | 92 | padding 1em 0 |
index 273c774..83a48d4 | |||
old size: 5K - new size: 5K | |||
@@ -191,5 +191,13 @@ p > code | |||
191 | 191 | white-space -moz-pre-wrap | |
192 | 192 | white-space -o-pre-wrap | |
193 | 193 | ||
194 | + | select | |
195 | + | -webkit-appearance none | |
196 | + | -moz-appearance none | |
197 | + | appearance none | |
198 | + | background transparent | |
199 | + | border 0 | |
200 | + | cursor pointer | |
201 | + | ||
194 | 202 | ul, ol | |
195 | 203 | margin 1.2em 2em |
index 521cc57..527a76d | |||
old size: 4K - new size: 4K | |||
@@ -79,12 +79,12 @@ | |||
79 | 79 | ||
80 | 80 | <div class="more"> | |
81 | 81 | {% if page_number > 0 %} | |
82 | - | <a href="{{ url ('homepage') if page_number == 1 else '?page=' ~ (page_number - 1) }}" class="button button_default1"> | |
82 | + | <a href="{{ request.urlparts.path if page_number == 1 else '?page=' ~ (page_number - 1) }}" class="button button_default1"> | |
83 | 83 | Previous | |
84 | 84 | </a> | |
85 | 85 | {% endif %} | |
86 | 86 | ||
87 | - | <a href="?page={{ page_number + 1 }}" class="button button_default1"> | |
87 | + | <a href="?page={{ page_number + 1 }}{{ '&sort=' ~ request.query.sort }}" class="button button_default1"> | |
88 | 88 | Next | |
89 | 89 | </a> | |
90 | 90 | </div> |
index a583fab..4aae247 | |||
old size: 4K - new size: 5K | |||
@@ -15,38 +15,62 @@ | |||
15 | 15 | <div class="container"> | |
16 | 16 | ||
17 | 17 | <div class="header"> | |
18 | - | <div class="menu"> | |
19 | - | <a href="/" class="flex-item logo"> | |
20 | - | freepost | |
18 | + | <div> | |
19 | + | {% if topic %} | |
20 | + | <a href="{{ url ('topic', name=topic) }}" class="flex-item logo"> | |
21 | + | topic / {{ topic }} | |
22 | + | </a> | |
23 | + | {% else %} | |
24 | + | <a href="{{ url ('homepage') }}" class="flex-item logo"> | |
25 | + | freepost | |
26 | + | </a> | |
27 | + | {% endif %} | |
28 | + | ||
29 | + | <a href="{{ url ('homepage') }}" class="flex-item logo"> | |
21 | 30 | <img alt="🐵 " title="freepost" src="/images/freepost.png" class="monkey" /> | |
22 | 31 | </a> | |
23 | - | <a href="/" class="flex-item {{ "active_page" if active_page == "hot" else "" }}">Hot</a> | |
24 | - | <a href="/new" class="flex-item {{ "active_page" if active_page == "new" else "" }}">New</a> | |
25 | - | <a href="/search" class="flex-item {{ "active_page" if active_page == "search" else "" }}">Search</a> | |
26 | - | ||
27 | - | {% if user %} | |
28 | - | {% set unread_messages = new_messages (user.id) %} | |
29 | - | ||
30 | - | <a href="/submit" class="flex-item {{ "active_page" if active_page == "submit" else "" }}">Submit</a> | |
32 | + | </div> | |
33 | + | ||
34 | + | <div> | |
35 | + | <div class="menu"> | |
36 | + | <a href="{{ url ('topic', name=topic) if topic else url ('homepage') }}" class="flex-item {{ 'active_page' if active_page == 'hot' }}"> | |
37 | + | Hot | |
38 | + | </a> | |
39 | + | <a href="{{ url ('topic', name=topic) if topic else url ('homepage') }}?sort=new" class="flex-item {{ 'active_page' if active_page == 'new' }}"> | |
40 | + | New | |
41 | + | </a> | |
31 | 42 | ||
32 | - | {% if unread_messages %} | |
33 | - | <a href="/user_activity/replies" class="new_messages flex-item"> | |
34 | - | {{ user.username }} ({{ unread_messages }}) | |
43 | + | {% if user %} | |
44 | + | <a href="{{ url ('submit') }}{{ '?topic=' ~ topic if topic }}" class="flex-item {{ 'active_page' if active_page == 'submit' }}"> | |
45 | + | Submit | |
35 | 46 | </a> | |
47 | + | {% endif %} | |
48 | + | ||
49 | + | <a href="{{ url ('search') }}" class="flex-item {{ 'active_page' if active_page == 'search' }}">Search</a> | |
50 | + | ||
51 | + | <a href="{{ url ('about') }}" class="flex-item {{ 'active_page' if active_page == 'about' }}">About</a> | |
52 | + | ||
53 | + | {% if user %} | |
54 | + | {% set unread_messages = new_messages (user.id) %} | |
55 | + | ||
56 | + | {% if unread_messages %} | |
57 | + | <a href="{{ url ('user_replies') }}" class="new_messages flex-item"> | |
58 | + | {{ user.username }} ({{ unread_messages }}) | |
59 | + | </a> | |
60 | + | {% else %} | |
61 | + | <a href="{{ url ('user_settings') }}" class="flex-item {{ 'active_page' if active_page == 'user' }}"> | |
62 | + | {{ user.username }} | |
63 | + | </a> | |
64 | + | {% endif %} | |
65 | + | ||
66 | + | <a href="{{ url ('logout') }}" class="flex-item">Log out</a> | |
36 | 67 | {% else %} | |
37 | - | <a href="/user" class="flex-item {{ "active_page" if active_page == "user" else "" }}"> | |
38 | - | {{ user.username }} | |
39 | - | </a> | |
68 | + | <a href="{{ url ('login') }}" class="flex-item {{ 'active_page' if active_page == 'login' }}">Log in</a> | |
40 | 69 | {% endif %} | |
41 | - | {% endif %} | |
42 | - | ||
43 | - | <a href="/about" class="flex-item {{ "active_page" if active_page == "about" else "" }}">About</a> | |
70 | + | </div> | |
44 | 71 | ||
45 | - | {% if user %} | |
46 | - | <a href="/logout" class="flex-item">Log out</a> | |
47 | - | {% else %} | |
48 | - | <a href="/login" class="flex-item {{ "active_page" if active_page == "login" else "" }}">Log in</a> | |
49 | - | {% endif %} | |
72 | + | <div class="submenu"> | |
73 | + | </div> | |
50 | 74 | </div> | |
51 | 75 | </div> | |
52 | 76 |
index f8883c3..0fd7c83 | |||
old size: 1K - new size: 1K | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | {% if settings ('defaults', 'topics_per_post') > 0 %} | |
30 | 30 | <h3>Topics</h3> | |
31 | 31 | <div> | |
32 | - | <input type="text" name="topics" class="form-control" /> | |
32 | + | <input type="text" name="topics" value="{{ request.query.topic }}" class="form-control" /> | |
33 | 33 | </div> | |
34 | 34 | <div> | |
35 | 35 | Max {{ settings ('defaults', 'topics_per_post') }} |
index 73a6b7e..73a6b7e | |||
old size: 2K - new size: 2K | |||