Add listing
This commit is contained in:
parent
8dd63e33f0
commit
fee5801db6
|
@ -46,8 +46,8 @@ class Slinky:
|
|||
Class for Slinky
|
||||
"""
|
||||
|
||||
def __init__(self, url: str) -> None:
|
||||
self.db = db.ShortcodeDB(url) # pylint: disable=invalid-name
|
||||
def __init__(self, db_url: str) -> None:
|
||||
self.db = db.ShortcodeDB(db_url) # pylint: disable=invalid-name
|
||||
self.session = self.db.session()
|
||||
|
||||
def add(
|
||||
|
@ -118,3 +118,15 @@ class Slinky:
|
|||
{db.ShortURL.fixed_views: db.ShortURL.fixed_views - 1}
|
||||
)
|
||||
self.session.commit()
|
||||
|
||||
def get_all(self) -> list[Shortcode]:
|
||||
"""
|
||||
Return a Shortcode object for a given shortcode
|
||||
|
||||
Args:
|
||||
shortcode (str): the shortcode to look up
|
||||
|
||||
Returns:
|
||||
Shortcode: full Shortcode object for the given shortcode
|
||||
"""
|
||||
return list(self.session.query(db.ShortURL).all())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% include '_head.html' %}
|
||||
{% include '_head.html' -%}
|
||||
|
||||
<!-- Begin page content -->
|
||||
<main class="container">
|
||||
|
@ -9,7 +9,7 @@
|
|||
<form action="/_/add" method="post">
|
||||
{{ form.url.label }} {{ form.url }}<br />
|
||||
{{ form.length.label }} {{ form.length }}<br />
|
||||
{{ form.fixed_views.label }} {{ form.fixed_views }} (0 = unlimited)<br />
|
||||
{{ form.fixed_views.label }} {{ form.fixed_views }} (-1 for unlimited)<br />
|
||||
{{ form.expiry.label}} {{ form.expiry(class='datepicker') }} (leave as default for unlimited)<br />
|
||||
|
||||
<button id="submit" class="btn btn-primary" type="submit" onclick="waiting();" style="margin: 1em 0;">
|
||||
|
@ -36,4 +36,4 @@
|
|||
</div>
|
||||
</main>
|
||||
|
||||
{% include '_tail.html' %}
|
||||
{% include '_tail.html' -%}
|
||||
|
|
35
slinky/templates/list.html
Normal file
35
slinky/templates/list.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% include '_head.html' -%}
|
||||
|
||||
<!-- Begin page content -->
|
||||
<main class="container">
|
||||
<div class="container">
|
||||
<h1 class="mt-5">Add a shortcode</h1>
|
||||
</div>
|
||||
<br />
|
||||
<div id="content">
|
||||
{% if shortcodes -%}
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Shortcode</th>
|
||||
<th scope="col">URL</th>
|
||||
<th scope="col">Remaining views</th>
|
||||
<th scope="col">Expiry date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for shortcode in shortcodes -%}
|
||||
<tr>
|
||||
<td>{{ shortcode.shortcode }}</td>
|
||||
<td><a href="{{shortcode.url}}">{{ shortcode.url }}</a></td>
|
||||
<td>{{ shortcode.fixed_views if shortcode.fixed_views >= 0 else 'Unlimited' }}</td>
|
||||
<td>{{ shortcode.expiry if shortcode.expiry != '9999-12-31 23:59:59.999999' else 'None' }}</td>
|
||||
</tr>
|
||||
{% endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif -%}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% include '_tail.html' -%}
|
|
@ -65,7 +65,7 @@ def try_path_as_shortcode(path: str) -> Response:
|
|||
Try the initial path as a shortcode, redirect if found
|
||||
|
||||
Returns:
|
||||
Optional[Response]: redirect if found, otherwise continue on
|
||||
Response: redirect if found, otherwise 404
|
||||
"""
|
||||
should_redirect = True
|
||||
slinky = Slinky(cfg['db'])
|
||||
|
@ -87,12 +87,12 @@ def try_path_as_shortcode(path: str) -> Response:
|
|||
|
||||
|
||||
@slinky_webapp.route('/_/add', methods=['GET', 'POST'])
|
||||
def add() -> str:
|
||||
def add() -> Response:
|
||||
"""
|
||||
Create and add a new shorturl
|
||||
|
||||
Returns:
|
||||
str: shortcode for the URL
|
||||
str: HTTP response
|
||||
"""
|
||||
shortcode = ''
|
||||
url = ''
|
||||
|
@ -107,11 +107,27 @@ def add() -> str:
|
|||
|
||||
if url:
|
||||
slinky = Slinky(cfg['db'])
|
||||
while True:
|
||||
for attempts in range(50):
|
||||
try:
|
||||
shortcode = slinky.add(url, length, fixed_views, expiry)
|
||||
break
|
||||
except ValueError:
|
||||
logging.warning('Shortcode already exists. Retrying.')
|
||||
logging.warning(
|
||||
'Shortcode already exists. Retrying (%d/50).', attempts
|
||||
)
|
||||
else:
|
||||
return Response('Could not create a unique shortcode', 500)
|
||||
|
||||
return render_template('add.html', form=form, shortcode=shortcode)
|
||||
|
||||
|
||||
@slinky_webapp.route('/_/list', methods=['GET', 'POST'])
|
||||
def lister() -> str:
|
||||
"""
|
||||
Create and add a new shorturl
|
||||
|
||||
Returns:
|
||||
str: shortcode for the URL
|
||||
"""
|
||||
slinky = Slinky(cfg['db'])
|
||||
return render_template('list.html', shortcodes=slinky.get_all())
|
||||
|
|
|
@ -89,6 +89,9 @@
|
|||
<li class="nav-item">
|
||||
<a class="nav-link" href="/_/add">Add</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/_/list">List</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -56,3 +56,15 @@ class TestSlinky(TestCase):
|
|||
Slinky(self.test_db).add,
|
||||
'https://www.example.com',
|
||||
)
|
||||
|
||||
def test_get_all(self) -> None:
|
||||
"""
|
||||
Ensure multiple results are returned and that they return all fields
|
||||
"""
|
||||
shortcodes = Slinky(self.test_db).get_all()
|
||||
|
||||
self.assertGreater(len(shortcodes), 1)
|
||||
assert hasattr(shortcodes[0], 'shortcode')
|
||||
assert hasattr(shortcodes[0], 'url')
|
||||
assert hasattr(shortcodes[0], 'fixed_views')
|
||||
assert hasattr(shortcodes[0], 'expiry')
|
||||
|
|
|
@ -6,6 +6,7 @@ from unittest import TestCase, mock
|
|||
|
||||
from slinky import web
|
||||
|
||||
|
||||
@mock.patch.dict('slinky.web.cfg', {'db': 'sqlite:///tests/test.db'})
|
||||
class TestWeb(TestCase):
|
||||
"""
|
||||
|
@ -33,3 +34,20 @@ class TestWeb(TestCase):
|
|||
"""
|
||||
response = web.try_path_as_shortcode('egif')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
@mock.patch(
|
||||
'slinky.web.ShortURLForm',
|
||||
return_value=mock.Mock(
|
||||
shortcode=mock.Mock(data=''),
|
||||
url=mock.Mock(data='https://example.com'),
|
||||
fixed_views=mock.Mock(data=0),
|
||||
expiry=mock.Mock(data='1970-01-01 00:00:00.000000'),
|
||||
),
|
||||
)
|
||||
@mock.patch('slinky.random_string', return_value='egie')
|
||||
def test_no_unique_shortcode(self, *_: Any) -> None:
|
||||
"""
|
||||
Ensure non-unique shortcodes return a 500 error
|
||||
"""
|
||||
response = web.add()
|
||||
self.assertEqual(response.status_code, 500)
|
||||
|
|
Loading…
Reference in a new issue