Skip to content

Load closest match pdf url #1173

Description

@jonfroehlich

I'm updating some code in #1166 that will regenerate some filenames. I'm worried about how this might create inaccurate links back to our website. I've already found instances using Google Search Console. For example, two of these links won't work after our file renames are completed:

  1. https://makeabilitylab.cs.washington.edu/media/publications/Gamifying_Green_Gamification_and_Environmental_Sustainability_yy7Jx99.pdf
  2. https://makeabilitylab.cs.washington.edu/media/publications/Froehlich_GrandChallengesInAccessibleMaps_2019.pdf
image

So, then I had the idea of writing a feature where--rather than loading a 404 page--if the specified PDF url is not found, we look for the closest PDF name in our database. I asked Copilot to help... and this seems like a good start:

Copilot

That sounds like a useful feature! You can achieve this by using a combination of Django views and a string similarity algorithm like Levenshtein distance to find the closest match. Here's a step-by-step guide:

1. Install the python-Levenshtein library:

pip install python-Levenshtein

2. Create a function to find the closest match:

import os
from Levenshtein import distance as levenshtein_distance

def find_closest_match(requested_filename, directory):
    files = os.listdir(directory)
    closest_match = None
    min_distance = float('inf')

    for file in files:
        if file.endswith('.pdf'):
            dist = levenshtein_distance(requested_filename, file)
            if dist < min_distance:
                min_distance = dist
                closest_match = file

    return closest_match if min_distance <= 5 else None  # Adjust threshold as needed

3. Create a Django view to handle the request:

from django.http import HttpResponse, Http404
from django.conf import settings
import os

def serve_pdf(request, filename):
    directory = os.path.join(settings.MEDIA_ROOT, 'pdfs')
    closest_match = find_closest_match(filename, directory)

    if closest_match:
        file_path = os.path.join(directory, closest_match)
        with open(file_path, 'rb') as pdf:
            response = HttpResponse(pdf.read(), content_type='application/pdf')
            response['Content-Disposition'] = f'inline; filename="{closest_match}"'
            return response
    else:
        raise Http404("PDF not found")

4. Update your urls.py:

from django.urls import path
from .views import serve_pdf

urlpatterns = [
    path('pdfs/<str:filename>/', serve_pdf, name='serve_pdf'),
]

This setup will attempt to find the closest matching PDF file based on the filename requested by the user and serve it if the similarity is within the defined threshold. Adjust the threshold in the find_closest_match function as needed to suit your requirements.
Would you like more details on any specific part of this process?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions