Skip to content

Commit

Permalink
Merge pull request #279 from Adithya14255/FinalPagination
Browse files Browse the repository at this point in the history
Final pagination
  • Loading branch information
kgashok authored Jun 19, 2024
2 parents f451e53 + 847e343 commit a1d979a
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 49 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ gunicorn
humanize
itsdangerous
jinja2
lxml
lxml_html_clean
markupsafe
maya
names
Expand Down
56 changes: 39 additions & 17 deletions saythanks/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from flask_qrcode import QRcode
from . import storage
from urllib.parse import quote
from lxml.html.clean import Cleaner
from lxml_html_clean import Cleaner
from markdown import markdown

cleaner = Cleaner()
Expand Down Expand Up @@ -85,13 +85,15 @@ def decorated(*args, **kwargs):

return decorated


# Application Routes
# ------------------


@app.route('/')
def index():
if 'search_str' in session:
session.pop('search_str', None)

return render_template('index.htm.j2',
callback_url=auth_callback_url,
auth_id=auth_id,
Expand All @@ -103,23 +105,42 @@ def index():
def inbox():
# Auth0 stored account information.
profile = session['profile']

# Grab the inbox from the database.
inbox_db = storage.Inbox(profile['nickname'])
is_enabled = storage.Inbox.is_enabled(inbox_db.slug)

# pagination
page = request.args.get('page', 1, type=int)
page_size = 25
# checking for invalid page numbers
if page < 0:
return render_template("404notfound.htm.j2")
data = inbox_db.notes(page, page_size)
if page > data['total_pages'] and data['total_pages']!=0:
return render_template("404notfound.htm.j2")
is_email_enabled = storage.Inbox.is_email_enabled(inbox_db.slug)
if request.method == "GET":

# handling search with pagination
if request.method == 'POST':
if 'clear' in request.form:
session.pop('search_str', None)
return redirect(url_for('inbox'))
else:
session['search_str'] = request.form['search_str']
# regular note set with pagination
if request.method == "GET" and 'search_str' not in session:
# Send over the list of all given notes for the user.
return render_template('inbox.htm.j2',
user=profile, notes=inbox_db.notes,
inbox=inbox_db, is_enabled=is_enabled,
is_email_enabled=is_email_enabled)
search_str = request.form['search_str']
user=profile, notes=data['notes'],
inbox=inbox_db, is_enabled=is_enabled,
is_email_enabled=is_email_enabled, page=data['page'],
total_pages=data['total_pages'], search_str="Search by message body or byline")
# reassessing data when search is used
if 'search_str' in session:
data = inbox_db.search_notes(session['search_str'], page, page_size)
return render_template('inbox.htm.j2',
user=profile, notes=inbox_db.search_notes(search_str),
is_email_enabled=is_email_enabled)

user=profile, notes=data['notes'],
is_email_enabled=is_email_enabled, page=data['page'],
total_pages=data['total_pages'], search_str=session['search_str'])


@app.route('/inbox/export/<format>')
Expand Down Expand Up @@ -210,8 +231,7 @@ def display_submit_note(inbox, topic):
if not storage.Inbox.does_exist(inbox):
abort(404)
elif not storage.Inbox.is_enabled(inbox):
abort(404)

abort(404)
fake_name = get_full_name()
topic_string = topic
if topic_string:
Expand All @@ -232,7 +252,10 @@ def share_note(uuid):
abort(404)

note = storage.Note.fetch(uuid)
return render_template('share_note.htm.j2', note=note)
note_body = note.body
for i in ['<div>', '<p>', '</div>', '</p>']:
note_body = note_body.replace(i, '')
return render_template('share_note.htm.j2', note=note, note_body=note_body)


@app.route('/inbox/archive/note/<uuid>', methods=['GET'])
Expand Down Expand Up @@ -278,7 +301,7 @@ def submit_note(inbox):
note = inbox_db.submit_note(body=body, byline=byline)
return redirect(url_for('thanks'))
# Strip any HTML away.

body = markdown(body)
body = remove_tags(body)
byline = Markup(request.form['byline']).striptags()
Expand Down Expand Up @@ -351,4 +374,3 @@ def callback_handling():
# Using nickname by default, can be changed manually later if needed.
storage.Inbox.store(nickname, userid, email)
return redirect(url_for('inbox'))

2 changes: 0 additions & 2 deletions saythanks/static/css/saythanks.css
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,6 @@ a.share {
animation: octocat-wave 560ms ease-in-out
}

#share {}

#message {}

#from {
Expand Down
10 changes: 10 additions & 0 deletions saythanks/static/css/skeleton.css
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,16 @@ hr {
border-top: 1px solid #E1E1E1;
}

.sharelinks{
display: flex;
gap:.2em;
}

.pagination{
display: flex;
justify-content: center;
gap:2em;
}

/* Clearing
–––––––––––––––––––––––––––––––––––––––––––––––––– */
Expand Down
62 changes: 48 additions & 14 deletions saythanks/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ def auth_id(self):
q = sqlalchemy.text("SELECT * FROM inboxes WHERE slug=:inbox")
r = conn.execute(q, inbox=self.slug).fetchall()
return r[0]['auth_id']

@classmethod
def is_linked(cls, auth_id):
q = sqlalchemy.text('SELECT * from inboxes where auth_id = :auth_id')
Expand Down Expand Up @@ -194,34 +193,69 @@ def myemail(self):
# print("myemail prop",emailinfo)
# return emailinfo

@property
def notes(self):
"""Returns a list of notes, ordered reverse-chronologically."""
q = sqlalchemy.text("SELECT * from notes where inboxes_auth_id = :auth_id and archived = 'f'")
r = conn.execute(q, auth_id=self.auth_id).fetchall()
def notes(self,page,page_size):
"""Returns a list of notes, ordered reverse-chronologically with pagination."""
offset = (page - 1) * page_size
count_query = sqlalchemy.text("SELECT COUNT(*) FROM notes WHERE inboxes_auth_id = :auth_id AND archived = 'f'")
total_notes = conn.execute(count_query, auth_id=self.auth_id).scalar()
query = sqlalchemy.text("""
SELECT * FROM notes
WHERE inboxes_auth_id = :auth_id AND archived = 'f'
ORDER BY timestamp DESC
LIMIT :limit OFFSET :offset
""")
result = conn.execute(query, auth_id=self.auth_id, limit=page_size, offset=offset).fetchall()

notes = [
Note.from_inbox(
self.slug,
n["body"], n["byline"], n["archived"], n["uuid"], n["timestamp"]
)
for n in r
for n in result
]
return notes[::-1]

return {
"notes": notes,
"total_notes": total_notes,
"page": page,
"total_pages": (total_notes + page_size - 1) // page_size # Calculate total pages
}

def search_notes(self, search_str):
"""Returns a list of notes, queried by search string "param" """
q = sqlalchemy.text("""SELECT * from notes where ( body LIKE '%' || :param || '%' or byline LIKE '%' || :param || '%' ) and inboxes_auth_id = :auth_id""")
r = conn.execute(q, param=search_str, auth_id=self.auth_id).fetchall()
def search_notes(self, search_str, page, page_size):
offset = (page - 1) * page_size

# Count total matching notes
count_query = sqlalchemy.text("""
SELECT COUNT(*) FROM notes
WHERE (body LIKE '%' || :param || '%' OR byline LIKE '%' || :param || '%')
AND inboxes_auth_id = :auth_id
""")
total_notes = conn.execute(count_query, param=search_str, auth_id=self.auth_id).scalar()

# Retrieve paginated notes
query = sqlalchemy.text("""
SELECT * FROM notes
WHERE (body LIKE '%' || :param || '%' OR byline LIKE '%' || :param || '%')
AND inboxes_auth_id = :auth_id
ORDER BY timestamp DESC
LIMIT :limit OFFSET :offset
""")
result = conn.execute(query, param=search_str, auth_id=self.auth_id, limit=page_size, offset=offset).fetchall()

notes = [
Note.from_inbox(
self.slug,
n["body"], n["byline"], n["archived"], n["uuid"], n["timestamp"]
)
for n in r
for n in result
]
return notes[::-1]

return {
"notes": notes,
"total_notes": total_notes,
"page": page,
"total_pages": (total_notes + page_size - 1) // page_size # Calculate total pages
}

def export(self, file_format):
q = sqlalchemy.text("SELECT * from notes where inboxes_auth_id = :auth_id and archived = 'f'")
Expand Down
12 changes: 12 additions & 0 deletions saythanks/templates/404notfound.htm.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>404 not found!</h1><br>
The page you requested does not exist
</body>
</html>
41 changes: 27 additions & 14 deletions saythanks/templates/inbox.htm.j2
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@
</p>

<form action="/inbox" method="POST">
<input type="text" style="font-size:14px" size=28 placeholder="Search by message body or byline" name="search_str">
<input type="text" style="font-size:14px" size=28 placeholder="{{search_str}}" name="search_str">
<button style="font-size:10px" type="submit">Search</button>
<button type="submit" name="clear" value="true">Clear</button>
</form>

<table>
<thead>
<tr>
<th id="share">Share URL</th>
<th id="share" style="padding:5px;">Share URL</th>
<th id="message">Message</th>
<th id="from">From</th>
<th id="timestamp">Timestamp</th>
Expand All @@ -88,32 +90,43 @@
<tbody>
{% for note in notes %}
<tr>
<td class="ellipsis">
<span>
<a class="share" href="{{ url_for('share_note', uuid=note.uuid)}}">🔗</a>
<a class="twitter-share-button" target="_blank" href="https://twitter.com/intent/tweet?text={{ note.body|quote + "%0A%0A- " + note.byline + "%0A%0A" + request.base_url[0:-6] + url_for('share_note', uuid=note.uuid) + "%0A" }}" data-url=" "></a> </br>
<iframe src="https://www.facebook.com/plugins/share_button.php?href={{ request.base_url[0:-6] + url_for('share_note', uuid=note.uuid) }}&layout=button&size=small&width=67&height=20&appId" width="67" height="20" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowfullscreen="true" allow="autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share">
</iframe>
</span>
</td>

<td class="ellipsis"><a class="share" href="{{ url_for('share_note', uuid=note.uuid)}}">🔗</a></td>
<td class="ellipsis"><a href="{{ url_for('share_note', uuid=note.uuid)}}"><span>{{ note.body }}</span></a></td>
<td class="ellipsis"><span>— {{ note.byline }}</span></td>
<td class="ellipsis">{{ note.timestamp.strftime('%d-%h-%Y %H:%M:%S') }}</td>
<td class="ellipsis"><strong><a class="share" href="{{ url_for('archive_note', uuid=note.uuid)}}">♻</a></strong></td>
</tr>
{% endfor %}

{% if (page==total_pages or total_pages==0) and search_str=="Search by message body or byline" %}
<tr>
<td></td>
<td>Thanks for using SayThanks.io! :)</td>
<td>Kenneth Reitz & Team</td>
<td></td>
<td></td>
</tr>
{%endif%}
</tbody>
</table>

</table><div class="pagination">
{% if total_pages!=0 %}
<a style="text-decoration:none;" href="{{ url_for('inbox', page=1) }}"><<</a>
{% if page > 1 %}
<a style="text-decoration:none;" href="{{ url_for('inbox', page=page-1) }}">Previous</a>
{% else %}
<span>Previous</span>
{% endif %}
<span> {{ page }} of {{ total_pages }}</span>
{% if page < total_pages %}
<a style="text-decoration:none;" href="{{ url_for('inbox', page=page+1) }}">Next</a>
{% else %}
<p>Next</p>
{% endif %}
<a style="text-decoration:none;" href="{{ url_for('inbox', page=total_pages) }}">>></a>
{% elif search_str!="Search by message body or byline" %}
<span> No matches found!
{% endif %}
</div>
<br><br><br><br>
<h4>Manage your Inbox:</h4>

<p>Below are some rudimentary account management tools, available, to you, today, for free!</p>
Expand Down
6 changes: 5 additions & 1 deletion saythanks/templates/share_note.htm.j2
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
<form action="../logout" method="POST">
<button type="submit" class="logoutLblPos" >Log Out</button>
</form>

<div class="sharelinks">
<a class="twitter-share-button" target="_blank" href="https://twitter.com/intent/tweet?text={{ note_body|quote + "%0A%0A- " + note.byline + "%0A%0A" + request.root_url + url_for('share_note', uuid=note.uuid)[1:] + "%0A" }}" data-url=" "></a> </br>
<iframe src="https://www.facebook.com/plugins/share_button.php?href={{ request.root_url + url_for('share_note', uuid=note.uuid)[1:] }}&layout=button&size=small&width=67&height=20&appId" width="67" height="20" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowfullscreen="true" allow="autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share"></iframe>
</div>
<br>
<form class="form-horizontal" action="./{{ user }}/submit" method="post">


Expand Down

0 comments on commit a1d979a

Please sign in to comment.