test_strava = 'This is dummy text with a strava embed {{strava:1234567}} here'
expected = 'This is dummy text with a strava embed <div class="border rounded p-4 text-center text-muted-foreground">🚴 Strava embed (full preview to see)</div> here'
assert replace_strava(test_strava)==expectedDialogue to deeal with the admin routes for my blog site. This includes editing and saving blog posts, though not as yet creating from scratch
Features still to be added 1. buttons on the relevant blog pages to allow edit - Done 2. buttons on the relevant blog pages to allow delete - Done 3. buttons on the relevant blog pages to allow download - Done 4. Add the capability to change tags for a post _still to do
route
def route(
path:NoneType=None
):
Decorator to collect routes without registering them immediately. Use @route(‘/path’) or @route() for function-name-based paths.
register_admin_routes
def register_admin_routes(
app, state
):
Register all collected routes with the app and setting state for the module
require_admin
def require_admin(
req
):
Call self as a function.
post_edit
def post_edit(
req, htmx, slug:str
):
Call self as a function.
save_post
def save_post(
htmx, slug:str, raw_post:str, return_to_blog:bool=False
):
Call self as a function.
The route admin/edit{slug} works well, I now need a route and function to delete a post based upon the slug and also one to download the the post content, title, tags, excerpt to a local markdown file with Obsidian format. Can you provide two functions to do that using the same approach as above
If the above is called from the blog page with the following: Button(“Delete”, hx_post=f”/admin/delete/{slug}“, hx_confirm=”Delete this post?“, cls=”uk-btn uk-btn-default uk-btn-xs”), then what will the Redirect cause to happen and how does this work with htmx?
If this was coming from a page with just the one post then that is fine but if it is coming from the main blog page with a list of posts, and this one has been chosen for deletion, then its only the main-content div that needs to be refreshed, hence should i not set a hx_target and target refreshing that?
I would prefer to do it the second way as I am keen to better understand how to deal with different htmx scenarios
delete_post
def delete_post(
req, htmx, slug:str
):
Call self as a function.
download_post
def download_post(
req, slug:str
):
Call self as a function.
In the above routes /admin/download/{slug}, delete_post(…), post_edit() I am concerned that if somebody on the web wanted to hack the site they could use the above routes to access or delete posts. Also some posts are private and should not be accessible (the main access points are protected). fasthtml_auth provides a decorator @auth.require_admin() but I am not sure how to use this with the way we are registering routes using the register_admin_routes methodology. We could also check for the user role using the req get user and check their role as an alternative. Do you agree this is a possible security issue and if so which of the above routes would you recommend to block it?
At present when using the download_post function I am setting the filename to the post title with .md. This is the way the post is initially created in Obscidian. Should I also save the slug and load it on subsequent uploads, since if somebody changes the title then when it creates a new slug all of the images will be lost etc?
Yes it does and so if a slug is present I can make it use that rather than recreate it
It should probably check if overwriting the existing post is what is required. I can use a hx_confirm to do this I think. The upload function is in core_v5 with the function process_upload. Some suggestion as to how to implement this would be useful
I can check for confirm in the route but I am not sure of the mechanism for generating the confirmation dialogue. Please give a consise example
So I don’t have a current id of upload-result, its only created by the dialogue, is that ok? I don’t understand the hx_vals structure, please explain. The current /admin/upload route definition is: @route(‘/admin/upload’)
def post(upload2: list[UploadFile], overwrite:bool=False): So I am not sure that the button to overwrite call is correct?
If I go down the first route then how will it then resume to doenload the other associated files?
Yes, pln you please outline the functions
Can you outline the flow please, I am a bit confused by the sequence. Lets start with the call to /admin/upload with the file list. Please be concise
No because the images are not saved first, the md file is, and it only makes sense to save the images if we know that the .md file is going to be saved
replace_iframe
def replace_iframe(
content:str
):
Comments re regex: The [^>] means not >, and so adding the means everything up to the >. The ? .?< makes the . non-greedy (lazy). Without it, if there were two iframes in the content, .* would greedily match from the first , swallowing everything in between — including any content between the two iframes. With .?, it stops at the nearest .
replace_strava
def replace_strava(
content:str
):
The strava pattern is: {{strava:16611889793}}
test_iframe_content = 'This is dummy text with an iframe <iframe src="https://www.google.com/maps/d/embed?mid=1NXlWhw7ZUcEQ_hGaXVAuuPz4DnGN_wQ&hl=en&ehbc=2E312F" width="640" height="480"></iframe> embedded'
expected = 'This is dummy text with an iframe <div class="border rounded p-4 text-center text-muted-foreground">iframe embed (full preview to see)</div> embedded'
assert replace_iframe(test_iframe_content) == expectedpost
def post(
raw_post:str, slug:str, full_render:bool=False
):
Call self as a function.
load_post
def load_post(
slug
):
Call self as a function.
edit_layout
def edit_layout(
req, content:VAR_POSITIONAL, htmx, title:NoneType=None
):
Call self as a function.
Export
nbdev.nbdev_export()