forked from forks/microblog.pub
Add alt text support for attachments
This commit is contained in:
parent
a95dee9ef0
commit
edae9a6b62
9 changed files with 74 additions and 12 deletions
|
@ -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
|
||||
|
|
32
alembic/versions/c9f204f5611d_alt_text_for_attachments.py
Normal file
32
alembic/versions/c9f204f5611d_alt_text_for_attachments.py
Normal 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 ###
|
|
@ -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,
|
||||
|
|
13
app/boxes.py
13
app/boxes.py
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue