Skip to content

Commit

Permalink
Ttl and text features (#6)
Browse files Browse the repository at this point in the history
* upgrade python and packages

* add ttl to ui; change html endpoint to preview; change text endpoint logic

* fix code style; tests; remove useless template

---------

Co-authored-by: antibantique <[email protected]>
  • Loading branch information
antavik and antibantique authored Jan 23, 2024
1 parent a8b9188 commit 2fe075a
Show file tree
Hide file tree
Showing 11 changed files with 50 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ FROM snakepacker/python:all as builder

ARG MODE=prod

RUN python3.10 -m venv /usr/share/python3/app
RUN python3.11 -m venv /usr/share/python3/app

# Setup python env
COPY ./requirements/ /etc/requirements/
Expand All @@ -23,7 +23,7 @@ RUN find-libdeps /usr/share/python3/app > /usr/share/python3/app/pkgdeps.txt
#################################################################
####################### TARGET STAGE ############################
#################################################################
FROM snakepacker/python:3.10
FROM snakepacker/python:3.11

ARG USER=app
ARG HOST=0.0.0.0
Expand Down
8 changes: 6 additions & 2 deletions app/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
clip_storage_key,
clip_task_name,
str2bool,
seconds_to_str_time,
)
from exceptions import InvalidParameters, StillProcessing

Expand All @@ -31,11 +32,14 @@ async def redirect(uid: str, storage: BaseStorage) -> str | None:
async def clip(
uid: str,
storage: BaseStorage
) -> tuple[str | None, dict[str, str] | None]:
) -> tuple[str | None, dict[str, str] | None, str]:
if clip_task_name(uid) in {f.get_name() for f in asyncio.all_tasks()}:
raise StillProcessing()

return await storage.multi_get(url_storage_key(uid), clip_storage_key(uid))
url, data = await storage.multi_get(url_storage_key(uid), clip_storage_key(uid)) # noqa
ttl = await storage.ttl(url_storage_key(uid))

return url, data, seconds_to_str_time(ttl)


async def shortify(
Expand Down
25 changes: 8 additions & 17 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,52 +93,43 @@ async def text_content(request: web.Request) -> web.Response:
storage = request.app['storage']

try:
url, data = await handlers.clip(uid, storage)
url, data, _ = await handlers.clip(uid, storage)
except StillProcessing:
return web.Response(status=202, text='Clip in process')

if url is None:
return web.Response(status=404, text='Clip not found')

if data:
html = await text_content_template.render_async(url=url, **data)
else:
html = await empty_content_template.render_async(url=url)

return web.Response(
status=200,
headers={
'Cache-Control': 'private, max-age=60',
},
headers={'Cache-Control': 'private, max-age=60'},
content_type='text/html',
charset='utf-8',
body=html
body=data['textContent'] if data else ''
)


@routes.get('/{uid}/html')
@routes.get('/{uid}/preview')
async def html_content(request: web.Request) -> web.Response:
uid = request.match_info['uid']
storage = request.app['storage']

try:
url, data = await handlers.clip(uid, storage)
url, data, ttl = await handlers.clip(uid, storage)
except StillProcessing:
return web.Response(status=202, text='Clip in process')

if url is None:
return web.Response(status=404, text='Clip not found')

if data:
html = await html_content_template.render_async(url=url, **data)
html = await html_content_template.render_async(url=url, ttl=ttl, **data) # noqa
else:
html = await empty_content_template.render_async(url=url)
html = await empty_content_template.render_async(url=url, ttl=ttl)

return web.Response(
status=200,
headers={
'Cache-Control': 'private, max-age=60',
},
headers={'Cache-Control': 'private, max-age=60'},
content_type='text/html',
charset='utf-8',
body=html
Expand Down
3 changes: 3 additions & 0 deletions app/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ async def multi_get(self, *keys: t.Any) -> t.Iterable[t.Any]:

return values

async def ttl(self, key: t.Any) -> int:
return await self._client.ttl(key)

async def set(
self,
key: t.Any,
Expand Down
5 changes: 5 additions & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
margin-left: 4%;
font-size: 18px;
}
.ttl {
font-size: 14px;
color: grey;
}
.content {
width: 70%;
}
Expand All @@ -47,6 +51,7 @@
<details class="src-url">
<summary>⚠️ Caution (source link) ⚠️</summary>
<a href="{{ url }}" target="_blank" rel="noopener noreferrer">{{ url }}</a>
<p class="ttl">ttl: {{ ttl }}</p>
</details>
</div>
</td>
Expand Down
5 changes: 0 additions & 5 deletions app/templates/text.html

This file was deleted.

5 changes: 5 additions & 0 deletions app/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ def ttl():
@pytest.fixture
def clip():
return {'test_content': 'test'}


@pytest.fixture
def random_int():
return random.randint(1000, 2000)
8 changes: 6 additions & 2 deletions app/tests/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ async def test_redirect__mocked_storage_value(mocked_storage, url, uid):

@pytest.mark.asyncio
async def test_clip__mocked_storage__value(mocked_storage, url, uid):
expected = (url, {'test_key', 'test_value'})
mocked_storage.multi_get.return_value = expected
mget_return = (url, {'test_key', 'test_value'})
ttl_return = 1000
expected = (*mget_return, utils.seconds_to_str_time(ttl_return))

mocked_storage.multi_get.return_value = mget_return
mocked_storage.ttl.return_value = ttl_return

with patch('handlers.clip_task_name') as mocked_clip_task_name:
result = await handlers.clip(uid, mocked_storage)
Expand Down
8 changes: 8 additions & 0 deletions app/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

import pytest

import utils
Expand Down Expand Up @@ -97,3 +99,9 @@ def test_str2bool___valid_inputes__valid_output(test_input, expected):
def test_str2bool__invalid_inputes__exception(test_input):
with pytest.raises(ValueError):
utils.str2bool(test_input)


def test_seconds_to_str_time__random_input__formated_str(random_int):
time = utils.seconds_to_str_time(random_int)

assert re.match(r'\d+h \d+m', time)
4 changes: 4 additions & 0 deletions app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def calc_seconds(number: int, unit: TimeUnit) -> int:
return calc(number)


def seconds_to_str_time(seconds: int) -> str:
return f'{seconds // 3600}h {seconds % 3600 // 60}m'


def url_storage_key(key: str) -> str:
return f'{LNK}-u:{key}'

Expand Down
6 changes: 3 additions & 3 deletions requirements/prod.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
aiohttp==3.8.*
aiohttp==3.9.*
redis[hiredis]==4.3.*
aioredis>=1.3,<2.0
Jinja2==3.1.*
ujson==5.4.0
uvloop==0.17.*
ujson==5.9.0
uvloop==0.19.*
shortuuid==1.0.11

0 comments on commit 2fe075a

Please sign in to comment.