Enquetes do Mastodon no ActivityPub
Publicado em
Eu comecei a rodar minha própria instância de ActivityPub usando o Takahē.
Me interessei em contribuir com o projeto e uma das primeiras funcionalidades que implementei foi o suporte a enquetes.
Enquanto eu implementava, notei que as informações sobre o assunto estavam espalhadas entre vários lugares diferentes.
Então, para que eu possa me lembrar do seu funcionamento, e para que talvez sirva de ajuda para alguém buscando pela mesma informação, eu decidi escrever este artigo.
Enquete ou Pergunta? Como o ActivityPub lida com este conceito?
A primeira coisa que precisamos compreender é que o ActivityPub não suporta enquetes (Poll na definição do mastodon) como um tipo nativo em sua definição de protocolo.
O tipo mais próximo seria o tipo Question que é usado para representar qualquer tipo de pergunta, incluindo perguntas abertas que é uma informação importante sobre o assunto para ter em mente.
Olhando na documentação do ActivityPub de como representar perguntas podemos ver sua estrutura:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://polls.example.org/question/1",
"type": "Question",
"content": "Qual é a resposta para a vida o universo e tudo mais?"
}
A pergunta acima é aberta, mas podemos ter perguntas de uma só resposta usando o atributo oneOf
:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://polls.example.org/question/2",
"type": "Question",
"content": "Qual é a resposta para a vida o universo e tudo mais?",
"oneOf":[
{ "name":"123" },
{ "name":"42" },
{ "name":"666" }
]
}
Podemos também ter perguntas de múltipla resposta usando o atributo anyOf
:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://polls.example.org/question/3",
"type": "Question",
"content": "Qual é a sua estação favorita?",
"anyOf":[
{ "name":"Primavera" },
{ "name":"Verão" },
{ "name":"Outono" },
{ "name":"Inverno" }
]
}
Quando não queremos parar de aceitar respostas para a pergunta, podemos indicar com o atributo closed
passando um DateTime
com o momento em que a pergunta foi fechada:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://polls.example.org/question/4",
"type": "Question",
"content": "Corre antes que acabe, quem quer um pedaço de bolo?",
"closed": "2023-01-01T00:00:00Z"
}
Estes são os atributos de base de uma pergunta no ActivityPub. Mais a frente veremos o que o Mastodon adicionou para fazer criar a enquete.
Respondendo a uma Pergunta
A resposta para uma pergunta em ActivityPub é um pouco vaga. Ela não tem um tipo específico, mas requer a existência de alguns atributos:
{
"@context": "https://www.w3.org/ns/activitystreams",
"attributedTo": "http://bob.example.org",
"inReplyTo": "http://polls.example.org/question/2",
"name": "42"
}
O atributo attributedTo
indica quem está respondendo a pergunta, enquanto o atributo inReplyTo
aponta para a URI da pergunta que estamos respondendo.
Embora não esteja mencionado na documentação, podemos inferir que o atributo name
é a resposta para a pergunta e, em perguntas onde temos escolhas à selecionar, o texto de resposta deve ser exatamente igual ao texto de uma das opções informadas na pergunta.
Agora que sabemos tudo que o ActivityPub tem a dizer a respeito do assunto, vamos ver como o Mastodon decidiu implementar esta funcionalidade.
A enquete no Mastodon
O Mastodon oferece alguns endpoints para lidar com enquetes:
GET /api/v1/polls/:id HTTP/1.1
para recuperar uma enquete (docs)POST /api/v1/polls/:id/votes HTTP/1.1
para votar em uma enquete (docs)POST /api/v1/statuses HTTP/1.1
para criar uma enquete através da API de status (docs)GET /api/v1/statuses/:id HTTP/1.1
para recuperar uma enquete através da API de status (docs)DELETE /api/v1/statuses/:id HTTP/1.1
para deletar uma enquete através da API de status (docs)
No momento em que estou escrevendo este artigo, uma entidade que representa uma enquete no Mastodon tem este formato:
{
"id": "12345",
"expires_at": "2023-01-01T23:04:45.000Z",
"expired": true,
"multiple": false,
"votes_count": 10,
"voters_count": null,
"options": [
{"title": "Opção 1", "votes_count": 6},
{"title": "Opção 2", "votes_count": 4},
],
"emojis": [],
"voted": false,
"own_votes": [],
}
O texto com a pergunta da enquete está localizado no atributo content
do status da mesma forma em que um post normal estaria.
Você pode acessar a documentation da entidade de enquetes para saber mais a respeito.
A enquete do Mastodon no ActivityPub
Voltando ao ActivityPub, uma enquete do Mastodon de fato usa o tipo Question
oferecido pelo ActivityPub, mas ele também adiciona alguns atributos para poder representar corretamente a enquete que recuperamos através da API do Mastodon.
A extensão toot
do mastodon é usada para adicionar o atributo votersCount
à enquete.
{
"@context":[
"https://www.w3.org/ns/activitystreams",
{
"toot":"http://joinmastodon.org/ns#",
"votersCount":"toot:votersCount"
},
"https://w3id.org/security/v1"
],
"id":"https://polls.example.org/users/sally/statuses/1234",
"type":"Question",
"votersCount":10,
"attributedTo":"https://polls.example.org/users/sally",
"closed":"2023-01-01T20:04:45Z",
"content":"<p>Qual é o seu pokemon inicial favorito?</p>",
"endTime":"2023-01-01T20:04:45Z",
"oneOf":[
{
"type":"Note",
"name":"Charmander",
"replies":{
"type":"Collection",
"totalItems":5
}
},
{
"type":"Note",
"name":"Bulbasauro",
"replies":{
"type":"Collection",
"totalItems":2
}
},
{
"type":"Note",
"name":"Squirtle",
"replies":{
"type":"Collection",
"totalItems":3
}
}
],
"published":"2023-01-01T01:00:00Z",
"url":"https://polls.example.org/@sally/1234"
}
O atributo endTime
é usado para adicionar um contador de tempo de expiração, enquanto closed
está presente somente quando uma enquete foi fechada. Ambos quando preenchidos devem ter o mesmo valor.
A extensão do votersCount
do Mastodon foi uma adição para dar suporte a questões de múltipla escolha, onde a soma dos votos pode ser diferente do número de participantes da enquete.
Também foi feita uma adaptação nas escolhas para contabilizar o número de votos por escolha:
{
"type":"Note",
"name":"Charmander",
"replies":{
"type":"Collection",
"totalItems":5
}
}
A escolha foi transformada em um objeto do tipo Note
que herda todos os atributos de Object
criando a possibilidade de usar o atributo replies
para guardar o total de votos de cada escolha.
O voto do Mastodon no ActivityPub
Para votar em uma enquete o Mastodon usa o mesmo processo indicado no ActivityPub, porém com pequenas diferenças:
{
"id":"https://answer.example.org/users/bob#votes/389574/activity",
"to":"https://polls.example.org/@sally@polls.example.org/",
"type":"Create",
"actor":"https://answer.example.org/users/bob",
"object":{
"id":"https://answer.example.org/users/bob#votes/389574",
"to":"https://polls.example.org/@sally@polls.example.org/",
"name":"Charmander",
"type":"Note",
"inReplyTo":"https://polls.example.org/@sally@polls.example.org/posts/1234/",
"attributedTo":"https://answer.example.org/users/bob"
},
"@context":[
"https://www.w3.org/ns/activitystreams",
{
"toot":"http://joinmastodon.org/ns#",
"votersCount":"toot:votersCount",
},
"https://w3id.org/security/v1"
]
}
O tipo do objeto usado é Note
para combinar com o tipo das opções de escolha.
Olhando para esta conversa no forum do ActivityPub sobre a implementação do voto no Mastodon, temos este resumo sobre os atributos do objeto:
id: ...
type: Note
name: <exatamente o mesmo texto da opção na enquete>
inreplyTo: <o status que contém a enquete>
attributedTo: <você>
to: <o criador da enquete>
Isto confirma que o Mastodon decidiu utilizar o que foi inferido sobre o atributo name
.
Quando lidando com enquetes de múltipla escolha o Mastodon, no lugar de alterar o formato do objeto para enviar todas respostas de uma só vez, foi preferido enviar mais de uma mensagem de Create
para a mesma enquete com cada uma das respostas selecionadas.
No final, para saber se a mensagem recebida é uma resposta para uma enquete, e não um post comum, é preciso verificar algumas coisas:
- O alvo do
inReplyTo
deve ser umaQuestion
- O tipo do objeto deve ser
Note
mas não possuí o atributocontent
- A resposta está localizada no atributo
name
Conclusão
Operações que utilizam o tipo Question
do ActivityPub não são muito claras quanto ao formato esperado e a documentação do Mastodon também não responde a todas as dúvidas deixadas pelo protocolo.
Entretanto espero que com estas informações você possa saber um pouco mais sobre seu funcionamento 🙂
Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional .