diff --git a/slinky/__init__.py b/slinky/__init__.py index f524612..69756ca 100644 --- a/slinky/__init__.py +++ b/slinky/__init__.py @@ -71,7 +71,7 @@ class Slinky: """ shortcode = random_string(length=length) - if self.get(shortcode).url: + if self.get_by_shortcode(shortcode).url: raise ValueError(f'Shortcode {shortcode} already exists') dbentry = db.ShortURL( @@ -85,7 +85,7 @@ class Slinky: return shortcode - def get(self, shortcode: str) -> Shortcode: + def get_by_shortcode(self, shortcode: str) -> Shortcode: """ Return a Shortcode object for a given shortcode @@ -130,3 +130,15 @@ class Slinky: Shortcode: full Shortcode object for the given shortcode """ return list(self.session.query(db.ShortURL).all()) + + def delete_by_shortcode(self, shortcode: str) -> None: + """ + Delete shortcode entry + + Args: + shortcode (str): Shortcode of entry to delete + """ + entry = self.session.query(db.ShortURL).filter_by(shortcode=shortcode).first() + + self.session.delete(entry) + self.session.commit() diff --git a/slinky/templates/add.html b/slinky/templates/add.html index 61d40c8..4851bae 100644 --- a/slinky/templates/add.html +++ b/slinky/templates/add.html @@ -28,7 +28,7 @@ - {{request.host_url}}{{ shortcode }} + {{request.host_url}}{{ shortcode }} diff --git a/slinky/templates/list.html b/slinky/templates/list.html index 8c5cd90..f9fd973 100644 --- a/slinky/templates/list.html +++ b/slinky/templates/list.html @@ -15,6 +15,7 @@ URL Remaining views Expiry date + @@ -24,6 +25,14 @@ {{ shortcode.url }} {{ shortcode.fixed_views if shortcode.fixed_views >= 0 else 'Unlimited' }} {{ shortcode.expiry if shortcode.expiry != '9999-12-31 23:59:59.999999' else 'None' }} + +
+ + +
+ {% endfor -%} diff --git a/slinky/web.py b/slinky/web.py index 66503af..755a459 100644 --- a/slinky/web.py +++ b/slinky/web.py @@ -8,7 +8,7 @@ from datetime import datetime import yaml from flask import Blueprint, Response, redirect, render_template from flask_wtf import FlaskForm -from wtforms import DateTimeLocalField, IntegerField, StringField +from wtforms import DateTimeLocalField, HiddenField, IntegerField, StringField from wtforms.validators import DataRequired, Length from slinky import Slinky @@ -19,9 +19,17 @@ with open('config.yaml', encoding='utf-8-sig') as conffile: cfg = yaml.safe_load(conffile) -class ShortURLForm(FlaskForm): # type: ignore[misc] +class DelForm(FlaskForm): # type: ignore[misc] """ - Web form definition + Delete form definition + """ + + delete = HiddenField('delete') + + +class AddForm(FlaskForm): # type: ignore[misc] + """ + Add form definition """ url = StringField( @@ -69,7 +77,7 @@ def try_path_as_shortcode(path: str) -> Response: """ should_redirect = True slinky = Slinky(cfg['db']) - shortcode = slinky.get(path) + shortcode = slinky.get_by_shortcode(path) if shortcode.url: if shortcode.fixed_views == 0: logging.warning('Shortcode out of views') @@ -97,7 +105,7 @@ def add() -> Response: shortcode = '' url = '' - form = ShortURLForm(meta={'csrf': False}) + form = AddForm(meta={'csrf': False}) if form.is_submitted(): url = form.url.data.strip() @@ -129,5 +137,10 @@ def lister() -> str: Returns: str: shortcode for the URL """ + form = DelForm(meta={'csrf': False}) slinky = Slinky(cfg['db']) - return render_template('list.html', shortcodes=slinky.get_all()) + + if form.is_submitted(): + slinky.delete_by_shortcode(form.delete.data.strip()) + + return render_template('list.html', form=form, shortcodes=slinky.get_all()) diff --git a/tests/test_slinky.py b/tests/test_slinky.py index 033571e..76af67b 100644 --- a/tests/test_slinky.py +++ b/tests/test_slinky.py @@ -43,7 +43,9 @@ class TestSlinky(TestCase): Ensure we can fetch a URL for a known shortcode """ - self.assertEqual('https://example.com', Slinky(self.test_db).get('egie').url) + self.assertEqual( + 'https://example.com', Slinky(self.test_db).get_by_shortcode('egie').url + ) @mock.patch('sqlalchemy.orm.session.Session.add', return_value=None) @mock.patch('slinky.random_string', return_value='egie') diff --git a/tests/test_web.py b/tests/test_web.py index 3f47f19..4dda8b6 100644 --- a/tests/test_web.py +++ b/tests/test_web.py @@ -47,7 +47,7 @@ class TestWeb(TestCase): @mock.patch('slinky.random_string', return_value='egie') def test_no_unique_shortcode(self, *_: Any) -> None: """ - Ensure non-unique shortcodes return a 500 error + Ensure non-unique shortcode generation returns a 500 error """ response = web.add() self.assertEqual(response.status_code, 500)