Add alt text support for attachments

This commit is contained in:
Thomas Sileo 2022-07-21 22:43:06 +02:00
parent a95dee9ef0
commit edae9a6b62
9 changed files with 74 additions and 12 deletions

View file

@ -30,7 +30,7 @@ It is still in early development, this README will be updated when I get to depl
- Strict access control for your outbox enforced via HTTP signature
- **No** Javascript
- The UI is pure HTML/CSS
- Except a tiny bit of hand-written JS in the note composer to insert emoji
- Except tiny bits of hand-written JS in the note composer to insert emoji and add alt text to images
- IndieWeb citizen
- [IndieAuth](https://www.w3.org/TR/indieauth/) support (OAuth2 extension)
- [Microformats](http://microformats.org/wiki/Main_Page) everywhere

View file

@ -0,0 +1,32 @@
"""Alt text for attachments
Revision ID: c9f204f5611d
Revises: 8ae9fc9ac88c
Create Date: 2022-07-21 22:33:41.569754
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = 'c9f204f5611d'
down_revision = '8ae9fc9ac88c'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('outbox_object_attachment', schema=None) as batch_op:
batch_op.add_column(sa.Column('alt', sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('outbox_object_attachment', schema=None) as batch_op:
batch_op.drop_column('alt')
# ### end Alembic commands ###

View file

@ -662,10 +662,12 @@ async def admin_actions_new(
) -> RedirectResponse:
# XXX: for some reason, no files restuls in an empty single file
uploads = []
raw_form_data = await request.form()
if len(files) >= 1 and files[0].filename:
for f in files:
upload = await save_upload(db_session, f)
uploads.append((upload, f.filename))
uploads.append((upload, f.filename, raw_form_data.get("alt_" + f.filename)))
public_id = await boxes.send_create(
db_session,
source=content,

View file

@ -286,7 +286,7 @@ async def send_undo(db_session: AsyncSession, ap_object_id: str) -> None:
async def send_create(
db_session: AsyncSession,
source: str,
uploads: list[tuple[models.Upload, str]],
uploads: list[tuple[models.Upload, str, str | None]],
in_reply_to: str | None,
visibility: ap.VisibilityEnum,
content_warning: str | None = None,
@ -315,8 +315,8 @@ async def send_create(
.values(replies_count=models.OutboxObject.replies_count + 1)
)
for (upload, filename) in uploads:
attachments.append(upload_to_attachment(upload, filename))
for (upload, filename, alt_text) in uploads:
attachments.append(upload_to_attachment(upload, filename, alt_text))
to = []
cc = []
@ -366,9 +366,12 @@ async def send_create(
)
db_session.add(tagged_object)
for (upload, filename) in uploads:
for (upload, filename, alt) in uploads:
outbox_object_attachment = models.OutboxObjectAttachment(
filename=filename, outbox_object_id=outbox_object.id, upload_id=upload.id
filename=filename,
alt=alt,
outbox_object_id=outbox_object.id,
upload_id=upload.id,
)
db_session.add(outbox_object_attachment)

View file

@ -77,7 +77,6 @@ _RESIZED_CACHE: MutableMapping[tuple[str, int], tuple[bytes, str, Any]] = LFUCac
#
# Next:
# - show pending follow request (and prevent double follow?)
# - a way to add alt text on image (maybe via special markup in content?)
# - UI support for updating posts
# - Support for processing update
# - Article support

View file

@ -234,7 +234,7 @@ class OutboxObject(Base, BaseObject):
{
"type": "Document",
"mediaType": attachment.upload.content_type,
"name": attachment.filename,
"name": attachment.alt or attachment.filename,
"url": url,
"proxiedUrl": url,
"resizedUrl": BASE_URL
@ -403,6 +403,7 @@ class OutboxObjectAttachment(Base):
id = Column(Integer, primary_key=True, index=True)
created_at = Column(DateTime(timezone=True), nullable=False, default=now)
filename = Column(String, nullable=False)
alt = Column(String, nullable=True)
outbox_object_id = Column(Integer, ForeignKey("outbox.id"), nullable=False)

View file

@ -30,3 +30,23 @@ var items = document.getElementsByClassName("ji")
for (var i = 0; i < items.length; i++) {
items[i].addEventListener('click', ji);
}
// Add new input text dynamically to allow setting an alt text on attachments
var files = document.getElementById("files");
var alts = document.getElementById("alts");
files.addEventListener("change", function(e) {
// Reset the div content
alts.innerHTML = "";
// Add an input for each files
for (var i = 0; i < e.target.files.length; i++) {
var p = document.createElement("p");
var altInput = document.createElement("input");
altInput.setAttribute("type", "text");
altInput.setAttribute("name", "alt_" + e.target.files[i].name);
altInput.setAttribute("placeholder", "Alt text for " + e.target.files[i].name);
altInput.setAttribute("style", "width:95%;")
p.appendChild(altInput);
alts.appendChild(p);
}
});

View file

@ -39,8 +39,9 @@
</p>
<input type="hidden" name="in_reply_to" value="{{ request.query_params.in_reply_to }}">
<p>
<input name="files" type="file" multiple>
<input id="files" name="files" type="file" multiple style="width:95%;">
</p>
<div id="alts"></div>
<p>
<input type="submit" value="Publish">
</p>

View file

@ -96,7 +96,11 @@ async def save_upload(db_session: AsyncSession, f: UploadFile) -> models.Upload:
return new_upload
def upload_to_attachment(upload: models.Upload, filename: str) -> ap.RawObject:
def upload_to_attachment(
upload: models.Upload,
filename: str,
alt_text: str | None,
) -> ap.RawObject:
extra_attachment_fields = {}
if upload.blurhash:
extra_attachment_fields.update(
@ -109,7 +113,7 @@ def upload_to_attachment(upload: models.Upload, filename: str) -> ap.RawObject:
return {
"type": "Document",
"mediaType": upload.content_type,
"name": filename,
"name": alt_text or filename,
"url": BASE_URL + f"/attachments/{upload.content_hash}/{filename}",
**extra_attachment_fields,
}