Compare commits
2 Commits
badb73098a
...
23337f8ab3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23337f8ab3 | ||
|
|
fbfedf4dac |
@@ -1,10 +1,12 @@
|
||||
from folkugat_web.api.router import get_router
|
||||
|
||||
from . import index, live, set_page
|
||||
from . import cartell, index, live, playlist, set_page
|
||||
|
||||
router = get_router()
|
||||
router.include_router(cartell.router)
|
||||
router.include_router(index.router)
|
||||
router.include_router(live.router)
|
||||
router.include_router(set_page.router)
|
||||
router.include_router(playlist.router)
|
||||
|
||||
__all__ = ["router"]
|
||||
|
||||
71
folkugat_web/api/routes/sessio/cartell.py
Normal file
71
folkugat_web/api/routes/sessio/cartell.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import dataclasses
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import HTTPException, Request, UploadFile
|
||||
from fastapi.params import File
|
||||
from folkugat_web.api.router import get_router
|
||||
from folkugat_web.fragments.sessio import cartell
|
||||
from folkugat_web.services import auth
|
||||
from folkugat_web.services import files as files_service
|
||||
from folkugat_web.services import sessions as sessions_service
|
||||
|
||||
router = get_router()
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/cartell")
|
||||
def get_cartell(
|
||||
request: Request,
|
||||
logged_in: auth.LoggedIn,
|
||||
session_id: int,
|
||||
):
|
||||
return cartell.cartell(request, session_id, logged_in)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/cartell/editor")
|
||||
def get_cartell_editor(
|
||||
request: Request,
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
):
|
||||
return cartell.cartell_editor(request, session_id)
|
||||
|
||||
|
||||
@router.put("/api/sessio/{session_id}/cartell")
|
||||
async def set_cartell(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
upload_file: Annotated[UploadFile, File()],
|
||||
):
|
||||
session = sessions_service.get_session(session_id=session_id)
|
||||
if not session:
|
||||
raise HTTPException(status_code=404, detail="Could not find session")
|
||||
url = await files_service.store_session_cartell(
|
||||
session_id=session_id,
|
||||
upload_file=upload_file,
|
||||
)
|
||||
new_session = dataclasses.replace(
|
||||
session,
|
||||
cartell_url=url,
|
||||
)
|
||||
sessions_service.set_session(new_session)
|
||||
return cartell.cartell(request, session_id, logged_in)
|
||||
|
||||
|
||||
@router.delete("/api/sessio/{session_id}/cartell")
|
||||
async def delete_cartell(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
):
|
||||
session = sessions_service.get_session(session_id=session_id)
|
||||
if not session:
|
||||
raise HTTPException(status_code=404, detail="Could not find session")
|
||||
if session.cartell_url:
|
||||
new_session = dataclasses.replace(
|
||||
session,
|
||||
cartell_url=None,
|
||||
)
|
||||
sessions_service.set_session(new_session)
|
||||
files_service.clean_orphan_files()
|
||||
return cartell.cartell(request, session_id, logged_in)
|
||||
@@ -2,7 +2,8 @@ from typing import Annotated
|
||||
|
||||
from fastapi import Form, Request
|
||||
from folkugat_web.api.router import get_router
|
||||
from folkugat_web.fragments import live, sessio
|
||||
from folkugat_web.fragments import live
|
||||
from folkugat_web.fragments.sessio import page as sessio
|
||||
from folkugat_web.services import auth
|
||||
from folkugat_web.services.temes import write as temes_service
|
||||
from folkugat_web.templates import templates
|
||||
@@ -52,150 +53,3 @@ def stop_live(
|
||||
session_id: int,
|
||||
):
|
||||
return live.stop_live_session(request=request, session_id=session_id)
|
||||
|
||||
|
||||
@router.post("/api/sessio/{session_id}/set")
|
||||
def add_set(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
):
|
||||
return sessio.add_set(request=request, session_id=session_id, logged_in=logged_in)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/set/{set_id}")
|
||||
def get_set(
|
||||
request: Request,
|
||||
logged_in: auth.LoggedIn,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
):
|
||||
return sessio.get_set(request=request, session_id=session_id, set_id=set_id, logged_in=logged_in)
|
||||
|
||||
|
||||
@router.delete("/api/sessio/{session_id}/set/{set_id}")
|
||||
def delete_set(
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
):
|
||||
return sessio.delete_set(session_id=session_id, set_id=set_id)
|
||||
|
||||
|
||||
@router.post("/api/sessio/{session_id}/set/{set_id}")
|
||||
def add_tema(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
):
|
||||
return sessio.add_tema(request=request, session_id=session_id, set_id=set_id, logged_in=logged_in)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}")
|
||||
def get_tema(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return sessio.get_tema(
|
||||
request=request, session_id=session_id, set_id=set_id, entry_id=entry_id, logged_in=logged_in)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}/editor")
|
||||
def get_tema_editor(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return sessio.get_tema_editor(
|
||||
request=request, session_id=session_id, set_id=set_id, entry_id=entry_id, logged_in=logged_in)
|
||||
|
||||
|
||||
@router.delete("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}")
|
||||
def delete_tema(
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return sessio.delete_tema(session_id=session_id, set_id=set_id, entry_id=entry_id)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}/busca")
|
||||
def busca_tema(
|
||||
request: Request,
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
query: str,
|
||||
):
|
||||
return sessio.busca_tema(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
query=query,
|
||||
)
|
||||
|
||||
|
||||
@router.put("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}")
|
||||
def set_tema(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
tema_id: Annotated[int, Form()],
|
||||
):
|
||||
return sessio.set_tema(
|
||||
request=request,
|
||||
logged_in=logged_in,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
tema_id=tema_id,
|
||||
)
|
||||
|
||||
|
||||
@router.put("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}/unknown")
|
||||
def set_tema_unknown(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return sessio.set_tema(
|
||||
request=request,
|
||||
logged_in=logged_in,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
tema_id=None,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/sessio/{session_id}/set/{set_id}/tema/{entry_id}")
|
||||
def set_tema_new(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
title: Annotated[str, Form()],
|
||||
):
|
||||
new_tema = temes_service.create_tema(title=title)
|
||||
return sessio.set_tema(
|
||||
request=request,
|
||||
logged_in=logged_in,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
tema_id=new_tema.id,
|
||||
)
|
||||
|
||||
189
folkugat_web/api/routes/sessio/playlist.py
Normal file
189
folkugat_web/api/routes/sessio/playlist.py
Normal file
@@ -0,0 +1,189 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Form, Request
|
||||
from folkugat_web.api.router import get_router
|
||||
from folkugat_web.fragments import live
|
||||
from folkugat_web.fragments.sessio import playlist
|
||||
from folkugat_web.services import auth
|
||||
from folkugat_web.services.temes import write as temes_service
|
||||
from folkugat_web.templates import templates
|
||||
|
||||
router = get_router()
|
||||
|
||||
|
||||
@router.post("/api/sessio/{session_id}/playlist/set")
|
||||
def add_set(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
):
|
||||
return playlist.add_set(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
logged_in=logged_in,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/playlist/set/{set_id}")
|
||||
def get_set(
|
||||
request: Request,
|
||||
logged_in: auth.LoggedIn,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
):
|
||||
return playlist.get_set(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
logged_in=logged_in,
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/api/sessio/{session_id}/playlist/set/{set_id}")
|
||||
def delete_set(
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
):
|
||||
return playlist.delete_set(
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/sessio/{session_id}/playlist/set/{set_id}")
|
||||
def add_tema(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
):
|
||||
return playlist.add_tema(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
logged_in=logged_in,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}")
|
||||
def get_tema(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return playlist.get_tema(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
logged_in=logged_in,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}/editor")
|
||||
def get_tema_editor(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return playlist.get_tema_editor(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
logged_in=logged_in,
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}")
|
||||
def delete_tema(
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return playlist.delete_tema(
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}/busca")
|
||||
def busca_tema(
|
||||
request: Request,
|
||||
_: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
query: str,
|
||||
):
|
||||
return playlist.busca_tema(
|
||||
request=request,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
query=query,
|
||||
)
|
||||
|
||||
|
||||
@router.put("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}")
|
||||
def set_tema(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
tema_id: Annotated[int, Form()],
|
||||
):
|
||||
return playlist.set_tema(
|
||||
request=request,
|
||||
logged_in=logged_in,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
tema_id=tema_id,
|
||||
)
|
||||
|
||||
|
||||
@router.put("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}/unknown")
|
||||
def set_tema_unknown(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
):
|
||||
return playlist.set_tema(
|
||||
request=request,
|
||||
logged_in=logged_in,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
tema_id=None,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/sessio/{session_id}/playlist/set/{set_id}/tema/{entry_id}")
|
||||
def set_tema_new(
|
||||
request: Request,
|
||||
logged_in: auth.RequireLogin,
|
||||
session_id: int,
|
||||
set_id: int,
|
||||
entry_id: int,
|
||||
title: Annotated[str, Form()],
|
||||
):
|
||||
new_tema = temes_service.create_tema(title=title)
|
||||
return playlist.set_tema(
|
||||
request=request,
|
||||
logged_in=logged_in,
|
||||
session_id=session_id,
|
||||
set_id=set_id,
|
||||
entry_id=entry_id,
|
||||
tema_id=new_tema.id,
|
||||
)
|
||||
@@ -34,7 +34,7 @@ async def set_link(
|
||||
upload_file: Annotated[UploadFile | None, File()] = None,
|
||||
):
|
||||
if upload_file:
|
||||
url = await files_service.store_file(tema_id=tema_id, upload_file=upload_file)
|
||||
url = await files_service.store_tema_file(tema_id=tema_id, upload_file=upload_file)
|
||||
|
||||
link_type = links_service.guess_link_type(url or '')
|
||||
new_link = model.Link(
|
||||
@@ -65,7 +65,7 @@ def create_link(
|
||||
|
||||
@router.delete("/api/tema/{tema_id}/link/{link_id}")
|
||||
def delete_link(
|
||||
_logged_in: auth.RequireLogin,
|
||||
_: auth.RequireLogin,
|
||||
tema_id: int,
|
||||
link_id: int,
|
||||
):
|
||||
|
||||
File diff suppressed because one or more lines are too long
36
folkugat_web/assets/templates/fragments/sessio/cartell.html
Normal file
36
folkugat_web/assets/templates/fragments/sessio/cartell.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<div id="cartell"
|
||||
class="flex flex-col items-center">
|
||||
{% if session.cartell_url %}
|
||||
<div class="max-w-[655px] w-full
|
||||
flex flex-col items-center">
|
||||
{% if logged_in %}
|
||||
<div class="my-2 w-full text-beige text-right">
|
||||
<button title="Modifica el cartell"
|
||||
class="mx-1"
|
||||
hx-get="/api/sessio/{{ session_id }}/cartell/editor"
|
||||
hx-target="#cartell"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button title="Esborra el cartell"
|
||||
class="mx-1"
|
||||
hx-delete="/api/sessio/{{ session_id }}/cartell"
|
||||
hx-target="#cartell"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<img class="w-full h-auto"
|
||||
src="{{ session.cartell_url }}"/>
|
||||
</div>
|
||||
{% elif logged_in %}
|
||||
<button class="text-beige mt-2"
|
||||
hx-get="/api/sessio/{{ session_id }}/cartell/editor"
|
||||
hx-target="#cartell"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||
Afegeix cartell
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
<form id="cartell-editor"
|
||||
class="flex flex-row gap-2"
|
||||
hx-encoding="multipart/form-data">
|
||||
<input type='file'
|
||||
class="border border-beige focus:outline-none
|
||||
rounded grow
|
||||
bg-brown p-1 my-1"
|
||||
name='upload_file'/>
|
||||
<button title="Desa els canvis"
|
||||
class="mx-1 text-beige"
|
||||
hx-put="/api/sessio/{{ session_id }}/cartell"
|
||||
hx-target="#cartell-editor"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-check" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button title="Descarta els canvis"
|
||||
class="mx-1 text-beige"
|
||||
hx-get="/api/sessio/{{ session_id }}/cartell"
|
||||
hx-target="#cartell-editor"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
@@ -12,6 +12,7 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
{% include "fragments/sessio/cartell.html" %}
|
||||
<div class="text-left">
|
||||
<h4 class="pt-4 text-xl text-beige">Horari i lloc</h4>
|
||||
De {{ session.start_time.strftime("%H:%M") }}
|
||||
@@ -29,6 +30,17 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if logged_in or session.notes %}
|
||||
<div class="text-left">
|
||||
<h4 class="py-4 text-xl text-beige">Notes</h4>
|
||||
{% if session.notes %}{{ session.notes }}{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if logged_in or False %}
|
||||
<div class="text-left">
|
||||
<h4 class="py-4 text-xl text-beige">Slow Jam</h4>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if logged_in or playlist.sets %}
|
||||
<div class="text-left">
|
||||
<h4 class="py-4 text-xl text-beige mt-2">Temes tocats</h4>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% if logged_in %}
|
||||
<div class="flex flex-col items-center">
|
||||
<button class="text-beige mt-2"
|
||||
hx-post="/api/sessio/{{ session.id }}/set"
|
||||
hx-post="/api/sessio/{{ session.id }}/playlist/set"
|
||||
hx-target="#playlist-{{ session.id }}"
|
||||
hx-swap="beforeend transition:true">
|
||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
m-4 rounded-lg bg-white
|
||||
px-2 py-1 my-1"
|
||||
id="set-entry-{{ set_id }}"
|
||||
hx-get="/api/sessio/{{ session_id }}/set/{{ set_id }}"
|
||||
hx-get="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}"
|
||||
hx-target="#set-entry-{{ set_id }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="reload-set-{{ set_id }}">
|
||||
{% if set_entry.temes | length > 1 or not set_entry.temes[0] %}
|
||||
{% if set_entry.temes | length > 1 or not set_entry.temes[0].tema %}
|
||||
{% set set_url = "/sessio/%d/set/%d" | format(session_id, set_id) %}
|
||||
{% else %}
|
||||
{% set set_url = "/tema/%d" | format(set_entry.temes[0].tema_id) %}
|
||||
{% endif %}
|
||||
<a href="{{ set_url }}"
|
||||
class="flex flex-row grow items-center cursor-pointer"
|
||||
title="Mostra els temes">
|
||||
{% if logged_in %}
|
||||
<div class="flex flex-row grow items-center">
|
||||
{% else %}
|
||||
<a href="{{ set_url }}"
|
||||
class="flex flex-row grow items-center cursor-pointer"
|
||||
title="Mostra els temes">
|
||||
{% endif %}
|
||||
<div class="flex-1"></div>
|
||||
<div class="flex flex-col
|
||||
items-start
|
||||
@@ -21,7 +25,7 @@
|
||||
w-full max-w-[655px]">
|
||||
{% if logged_in %}
|
||||
<button class="text-beige w-full"
|
||||
hx-delete="/api/sessio/{{ session_id }}/set/{{ set_id }}"
|
||||
hx-delete="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}"
|
||||
hx-target="#set-entry-{{ set_id }}"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
@@ -40,7 +44,7 @@
|
||||
</ol>
|
||||
{% if logged_in %}
|
||||
<button class="text-beige mt-2 w-full"
|
||||
hx-post="/api/sessio/{{ session_id }}/set/{{ set_id }}"
|
||||
hx-post="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}"
|
||||
hx-target="#set-entry-{{ set_id }}-list"
|
||||
hx-swap="beforeend transition:true">
|
||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||
@@ -49,7 +53,9 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex-1 text-beige">
|
||||
{% if logged_in %}<a href="{{ set_url }}" class="text-beige">{% endif %}
|
||||
<i class="fa fa-chevron-right" aria-hidden="true"></i>
|
||||
{% if logged_in %}</a>{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% if logged_in %}</div>{% else %}</a>{% endif %}
|
||||
</li>
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
class="border border-beige focus:outline-none
|
||||
rounded text-center text-black
|
||||
p-1 m-1"
|
||||
hx-get="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ tema_entry.id }}/busca"
|
||||
hx-get="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ tema_entry.id }}/busca"
|
||||
hx-trigger="revealed, keyup delay:500ms changed"
|
||||
hx-target="#tune-entry-{{ tema_entry.id }}-search-results"
|
||||
hx-swap="outerHTML"/>
|
||||
<button title="Descarta els canvis"
|
||||
class="text-beige mx-1"
|
||||
hx-get="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ tema_entry.id }}"
|
||||
hx-get="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ tema_entry.id }}"
|
||||
hx-target="#tune-entry-{{ tema_entry.id }}"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
<div class="flex-none flex flex-row shrink-0">
|
||||
<button title="Edita el tema"
|
||||
class="text-beige mx-1"
|
||||
hx-get="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ tema_entry.id }}/editor"
|
||||
hx-get="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ tema_entry.id }}/editor"
|
||||
hx-target="#tune-entry-{{ tema_entry.id }}"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button title="Esborra el tema"
|
||||
class="text-beige mx-1"
|
||||
hx-delete="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ tema_entry.id }}"
|
||||
hx-delete="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ tema_entry.id }}"
|
||||
hx-target="#tune-entry-{{ tema_entry.id }}"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<li>
|
||||
<button class="bg-beige text-brown rounded
|
||||
m-1 px-2"
|
||||
hx-put="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ entry_id }}"
|
||||
hx-put="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ entry_id }}"
|
||||
hx-vals='{"tema_id": "{{ tema.id }}"}'
|
||||
hx-target="#tune-entry-{{ entry_id }}"
|
||||
hx-swap="outerHTML">
|
||||
@@ -15,7 +15,7 @@
|
||||
<li>
|
||||
<button class="border border-beige text-beige rounded
|
||||
m-1 px-2"
|
||||
hx-put="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ entry_id }}/unknown"
|
||||
hx-put="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ entry_id }}/unknown"
|
||||
hx-target="#tune-entry-{{ entry_id }}"
|
||||
hx-swap="outerHTML">
|
||||
<i class="fa fa-question" aria-hidden="true"></i>
|
||||
@@ -25,7 +25,7 @@
|
||||
<li>
|
||||
<button class="border border-beige text-beige rounded
|
||||
m-1 px-2"
|
||||
hx-post="/api/sessio/{{ session_id }}/set/{{ set_id }}/tema/{{ entry_id }}"
|
||||
hx-post="/api/sessio/{{ session_id }}/playlist/set/{{ set_id }}/tema/{{ entry_id }}"
|
||||
hx-vals='{"title": "{{ query }}"}'
|
||||
hx-target="#tune-entry-{{ entry_id }}"
|
||||
hx-swap="outerHTML">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="border border-beige focus:outline-none
|
||||
rounded grow
|
||||
bg-brown p-1 my-1"
|
||||
name='upload_file'>
|
||||
name='upload_file'/>
|
||||
<button title="Afegeix un enllaç"
|
||||
class="border border-beige rounded px-2 py-1 my-1"
|
||||
hx-get="/api/tema/{{ link.tema_id }}/editor/link/{{ link.id }}/url"
|
||||
|
||||
@@ -12,6 +12,7 @@ logger.info(f"Using DB_DIR: {DB_DIR}")
|
||||
|
||||
DB_FILES_DIR = DB_DIR / "fitxer"
|
||||
DB_FILES_TEMA_DIR = DB_FILES_DIR / "tema"
|
||||
DB_FILES_SESSION_DIR = DB_FILES_DIR / "sessio"
|
||||
DB_FILES_SET_DIR = DB_FILES_DIR / "set"
|
||||
DB_FILES_TMP_DIR = DB_FILES_DIR / "tmp"
|
||||
|
||||
|
||||
@@ -59,13 +59,15 @@ def get_playlist_entries(
|
||||
return map(conversion.row_to_playlist_entry, cur.fetchall())
|
||||
|
||||
|
||||
GetTuneSessionsRow = tuple[int, int, str, str, str, str | None, str | None, bool]
|
||||
GetTuneSessionsRow = tuple[int, int, str, str, str, str | None, str | None, str | None, str | None, bool]
|
||||
|
||||
|
||||
def get_tune_sessions(tema_ids: list[int], con: Connection | None = None) -> dict[int, list[Session]]:
|
||||
placeholders = ", ".join(["?" for _ in tema_ids])
|
||||
query = f"""
|
||||
SELECT p.tema_id, s.id, s.date, s.start_time, s.end_time, s.venue_name, s.venue_url, s.is_live
|
||||
SELECT
|
||||
p.tema_id, s.id, s.date, s.start_time, s.end_time, s.venue_name,
|
||||
s.venue_url, s.notes, s.cartell_url, s.is_live
|
||||
FROM playlists p JOIN sessions s ON p.session_id = s.id
|
||||
WHERE p.tema_id IN ({placeholders})
|
||||
"""
|
||||
|
||||
@@ -3,7 +3,17 @@ from typing import TypedDict
|
||||
|
||||
from folkugat_web.model import sessions as model
|
||||
|
||||
SessionRowTuple = tuple[int, str, str, str, str | None, str | None, bool]
|
||||
SessionRowTuple = tuple[
|
||||
int, # id
|
||||
str, # date
|
||||
str, # start_time
|
||||
str, # end_time
|
||||
str | None, # venue_name
|
||||
str | None, # venue_url
|
||||
str | None, # notes
|
||||
str | None, # cartell_url
|
||||
bool, # is_live
|
||||
]
|
||||
|
||||
|
||||
class SessionRowDict(TypedDict):
|
||||
@@ -13,6 +23,8 @@ class SessionRowDict(TypedDict):
|
||||
end_time: str
|
||||
venue_name: str | None
|
||||
venue_url: str | None
|
||||
notes: str | None
|
||||
cartell_url: str | None
|
||||
is_live: bool
|
||||
|
||||
|
||||
@@ -24,6 +36,8 @@ def session_to_row(sessio: model.Session) -> SessionRowDict:
|
||||
'end_time': sessio.end_time.isoformat(),
|
||||
'venue_name': sessio.venue.name,
|
||||
'venue_url': sessio.venue.url,
|
||||
'notes': sessio.notes,
|
||||
'cartell_url': sessio.cartell_url,
|
||||
'is_live': sessio.is_live,
|
||||
}
|
||||
|
||||
@@ -38,5 +52,7 @@ def row_to_session(row: SessionRowTuple) -> model.Session:
|
||||
name=row[4],
|
||||
url=row[5],
|
||||
),
|
||||
is_live=row[6],
|
||||
notes=row[6],
|
||||
cartell_url=row[7],
|
||||
is_live=row[8],
|
||||
)
|
||||
|
||||
@@ -15,6 +15,8 @@ def create_sessions_table(con: Connection):
|
||||
end_time TEXT NOT NULL,
|
||||
venue_name TEXT,
|
||||
venue_url TEXT,
|
||||
notes TEXT,
|
||||
cartell_url TEXT,
|
||||
is_live BOOLEAN DEFAULT false
|
||||
)
|
||||
"""
|
||||
|
||||
@@ -82,7 +82,7 @@ def get_sessions(session_id: int | None = None,
|
||||
|
||||
clauses_str = " ".join(clauses)
|
||||
query = f"""
|
||||
SELECT id, date, start_time, end_time, venue_name, venue_url, is_live
|
||||
SELECT id, date, start_time, end_time, venue_name, venue_url, notes, cartell_url, is_live
|
||||
FROM sessions
|
||||
{clauses_str}
|
||||
"""
|
||||
|
||||
@@ -7,9 +7,9 @@ from . import conversion
|
||||
def insert_session(session: model.Session, con: Connection | None = None):
|
||||
query = """
|
||||
INSERT INTO sessions
|
||||
(id, date, start_time, end_time, venue_name, venue_url, is_live)
|
||||
(id, date, start_time, end_time, venue_name, venue_url, notes, cartell_url, is_live)
|
||||
VALUES
|
||||
(:id, :date, :start_time, :end_time, :venue_name, :venue_url, :is_live)
|
||||
(:id, :date, :start_time, :end_time, :venue_name, :venue_url, :notes, :cartell_url, :is_live)
|
||||
RETURNING *
|
||||
"""
|
||||
data = conversion.session_to_row(session)
|
||||
@@ -24,7 +24,8 @@ def update_session(session: model.Session, con: Connection | None = None):
|
||||
query = """
|
||||
UPDATE sessions SET
|
||||
date = :date, start_time = :start_time, end_time = :end_time,
|
||||
venue_name = :venue_name, venue_url = :venue_url, is_live = :is_live
|
||||
venue_name = :venue_name, venue_url = :venue_url,
|
||||
notes = :notes, cartell_url = :cartell_url, is_live = :is_live
|
||||
WHERE id = :id
|
||||
"""
|
||||
data = conversion.session_to_row(session)
|
||||
|
||||
0
folkugat_web/fragments/sessio/__init__.py
Normal file
0
folkugat_web/fragments/sessio/__init__.py
Normal file
31
folkugat_web/fragments/sessio/cartell.py
Normal file
31
folkugat_web/fragments/sessio/cartell.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from fastapi import Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from folkugat_web.model.pagines import Pages
|
||||
from folkugat_web.services import playlists as playlists_service
|
||||
from folkugat_web.services import sessions as sessions_service
|
||||
from folkugat_web.services.temes import query as query_service
|
||||
from folkugat_web.services.temes import search as search_service
|
||||
from folkugat_web.templates import templates
|
||||
|
||||
|
||||
def cartell(request: Request, session_id: int, logged_in: bool):
|
||||
session = sessions_service.get_session(session_id=session_id)
|
||||
return templates.TemplateResponse(
|
||||
"fragments/sessio/cartell.html",
|
||||
{
|
||||
"request": request,
|
||||
"logged_in": logged_in,
|
||||
"session_id": session_id,
|
||||
"session": session,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def cartell_editor(request: Request, session_id: int):
|
||||
return templates.TemplateResponse(
|
||||
"fragments/sessio/cartell_editor.html",
|
||||
{
|
||||
"request": request,
|
||||
"session_id": session_id,
|
||||
}
|
||||
)
|
||||
25
folkugat_web/fragments/sessio/page.py
Normal file
25
folkugat_web/fragments/sessio/page.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from fastapi import HTTPException, Request
|
||||
from folkugat_web.model.pagines import Pages
|
||||
from folkugat_web.services import playlists as playlists_service
|
||||
from folkugat_web.services import sessions as sessions_service
|
||||
from folkugat_web.templates import templates
|
||||
|
||||
|
||||
def pagina(request: Request, session_id: int, logged_in: bool):
|
||||
session = sessions_service.get_session(session_id=session_id)
|
||||
if not session:
|
||||
raise HTTPException(status_code=404, detail="Could not find session")
|
||||
playlist = playlists_service.get_playlist(session_id=session_id)
|
||||
playlist = playlists_service.add_temes_to_playlist(playlist)
|
||||
return templates.TemplateResponse(
|
||||
"fragments/sessio/pagina.html",
|
||||
{
|
||||
"request": request,
|
||||
"logged_in": logged_in,
|
||||
"Pages": Pages,
|
||||
"session_id": session_id,
|
||||
"session": session,
|
||||
"playlist": playlist,
|
||||
"date_names": sessions_service.get_date_names,
|
||||
}
|
||||
)
|
||||
@@ -8,24 +8,6 @@ from folkugat_web.services.temes import search as search_service
|
||||
from folkugat_web.templates import templates
|
||||
|
||||
|
||||
def pagina(request: Request, session_id: int, logged_in: bool):
|
||||
session = sessions_service.get_session(session_id=session_id)
|
||||
playlist = playlists_service.get_playlist(session_id=session_id)
|
||||
playlist = playlists_service.add_temes_to_playlist(playlist)
|
||||
return templates.TemplateResponse(
|
||||
"fragments/sessio/pagina.html",
|
||||
{
|
||||
"request": request,
|
||||
"logged_in": logged_in,
|
||||
"Pages": Pages,
|
||||
"session_id": session_id,
|
||||
"session": session,
|
||||
"playlist": playlist,
|
||||
"date_names": sessions_service.get_date_names,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def add_set(request: Request, session_id: int, logged_in: bool):
|
||||
new_set = playlists_service.add_set(session_id=session_id)
|
||||
return templates.TemplateResponse(
|
||||
@@ -19,6 +19,8 @@ class Session:
|
||||
start_time: datetime.time = DEFAULT_START_TIME
|
||||
end_time: datetime.time = DEFAULT_END_TIME
|
||||
venue: SessionVenue = dataclasses.field(default_factory=SessionVenue)
|
||||
notes: str | None = None
|
||||
cartell_url: str | None = None
|
||||
is_live: bool = False
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import mimetypes
|
||||
import os
|
||||
import re
|
||||
import uuid
|
||||
from collections.abc import Iterator
|
||||
from collections.abc import Iterable, Iterator
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
@@ -11,6 +11,7 @@ import aiofiles
|
||||
import magic
|
||||
from fastapi import HTTPException, UploadFile
|
||||
from folkugat_web.config import db
|
||||
from folkugat_web.dal.sql.sessions import query as sessions_dal
|
||||
from folkugat_web.dal.sql.temes import links as links_dal
|
||||
from folkugat_web.dal.sql.temes import scores as scores_dal
|
||||
from folkugat_web.log import logger
|
||||
@@ -22,22 +23,16 @@ async def get_mimetype(upload_file: UploadFile) -> str:
|
||||
return info.mime_type
|
||||
|
||||
|
||||
ACCEPTED_MIMETYPES = [
|
||||
re.compile(r"image/.+"),
|
||||
re.compile(r".+/pdf"),
|
||||
]
|
||||
IMAGE_MIMETYPE = re.compile(r"image/.+")
|
||||
PDF_MIMETYPE = re.compile(r".+/pdf")
|
||||
|
||||
|
||||
def check_mimetype(mimetype: str) -> None:
|
||||
if not any(regex.match(mimetype) for regex in ACCEPTED_MIMETYPES):
|
||||
def check_mimetype(mimetype: str, accepted_mimetypes: Iterable[re.Pattern[str]]) -> None:
|
||||
if not any(regex.match(mimetype) for regex in accepted_mimetypes):
|
||||
raise HTTPException(status_code=400, detail=f"Unsupported file type: {mimetype}")
|
||||
|
||||
|
||||
def get_db_file_path(filepath: Path) -> str:
|
||||
return f"{db.DB_FILES_URL}/{filepath.relative_to(db.DB_FILES_DIR)}"
|
||||
|
||||
|
||||
async def store_file(tema_id: int, upload_file: UploadFile) -> str:
|
||||
def check_upload_file_size(upload_file: UploadFile) -> None:
|
||||
if not upload_file.size:
|
||||
raise HTTPException(status_code=400, detail="Couldn't find out the size of the file")
|
||||
if upload_file.size > db.FILE_MAX_SIZE:
|
||||
@@ -46,8 +41,15 @@ async def store_file(tema_id: int, upload_file: UploadFile) -> str:
|
||||
detail=f"The uploaded file is too big (max size = {db.FILE_MAX_SIZE} bytes)",
|
||||
)
|
||||
|
||||
|
||||
def get_db_file_path(filepath: Path) -> str:
|
||||
return f"{db.DB_FILES_URL}/{filepath.relative_to(db.DB_FILES_DIR)}"
|
||||
|
||||
|
||||
async def store_tema_file(tema_id: int, upload_file: UploadFile) -> str:
|
||||
check_upload_file_size(upload_file)
|
||||
mimetype = await get_mimetype(upload_file)
|
||||
check_mimetype(mimetype)
|
||||
check_mimetype(mimetype, [IMAGE_MIMETYPE, PDF_MIMETYPE])
|
||||
|
||||
extension = mimetypes.guess_extension(mimetype) or ""
|
||||
filepath = create_tema_filename(tema_id=tema_id, extension=extension)
|
||||
@@ -58,6 +60,20 @@ async def store_file(tema_id: int, upload_file: UploadFile) -> str:
|
||||
return get_db_file_path(filepath)
|
||||
|
||||
|
||||
async def store_session_cartell(session_id: int, upload_file: UploadFile) -> str:
|
||||
check_upload_file_size(upload_file)
|
||||
mimetype = await get_mimetype(upload_file)
|
||||
check_mimetype(mimetype, [IMAGE_MIMETYPE])
|
||||
|
||||
extension = mimetypes.guess_extension(mimetype) or ""
|
||||
filepath = create_cartell_filename(session_id=session_id, extension=extension)
|
||||
|
||||
with open(filepath, "wb") as f:
|
||||
_ = f.write(await upload_file.read())
|
||||
|
||||
return get_db_file_path(filepath)
|
||||
|
||||
|
||||
def create_tema_filename(tema_id: int, extension: str = "") -> Path:
|
||||
filename = str(uuid.uuid4().hex) + extension
|
||||
filedir = db.DB_FILES_TEMA_DIR / str(tema_id)
|
||||
@@ -66,6 +82,14 @@ def create_tema_filename(tema_id: int, extension: str = "") -> Path:
|
||||
return filepath
|
||||
|
||||
|
||||
def create_cartell_filename(session_id: int, extension: str = "") -> Path:
|
||||
filename = str(uuid.uuid4().hex) + extension
|
||||
filedir = db.DB_FILES_SESSION_DIR / str(session_id) / "cartell"
|
||||
filedir.mkdir(parents=True, exist_ok=True)
|
||||
filepath = filedir / filename
|
||||
return filepath
|
||||
|
||||
|
||||
def create_tmp_filename(extension: str = "") -> Path:
|
||||
filename = str(uuid.uuid4().hex) + extension
|
||||
filepath = db.DB_FILES_TMP_DIR / filename
|
||||
@@ -94,11 +118,13 @@ def list_files(tema_id: str) -> list[str]:
|
||||
|
||||
|
||||
def get_orphan_files() -> Iterator[Path]:
|
||||
link_urls = {link.url for link in links_dal.get_links()}
|
||||
score_pdf_urls = {score.pdf_url for score in scores_dal.get_scores() if score.pdf_url is not None}
|
||||
score_img_urls = {score.img_url for score in scores_dal.get_scores() if score.img_url is not None}
|
||||
score_preview_urls = {score.preview_url for score in scores_dal.get_scores() if score.preview_url is not None}
|
||||
alive_urls = link_urls | score_pdf_urls | score_img_urls | score_preview_urls
|
||||
alive_urls = (
|
||||
{link.url for link in links_dal.get_links()}
|
||||
| {score.pdf_url for score in scores_dal.get_scores() if score.pdf_url is not None}
|
||||
| {score.img_url for score in scores_dal.get_scores() if score.img_url is not None}
|
||||
| {score.preview_url for score in scores_dal.get_scores() if score.preview_url is not None}
|
||||
| {session.cartell_url for session in sessions_dal.get_sessions() if session.cartell_url}
|
||||
)
|
||||
return filter(
|
||||
lambda p: p.is_file() and get_db_file_path(p) not in alive_urls,
|
||||
itertools.chain(
|
||||
|
||||
10
scripts/04_add_session_notes_i_cartell.py
Normal file
10
scripts/04_add_session_notes_i_cartell.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from folkugat_web.dal.sql import get_connection
|
||||
|
||||
with get_connection() as con:
|
||||
cur = con.cursor()
|
||||
alter_query_1 = """ ALTER TABLE sessions ADD COLUMN notes TEXT """
|
||||
alter_query_2 = """ ALTER TABLE sessions ADD COLUMN cartell_url TEXT """
|
||||
_ = cur.execute(alter_query_1)
|
||||
_ = cur.execute(alter_query_2)
|
||||
|
||||
print("DONE!")
|
||||
Reference in New Issue
Block a user