parent
9a2a68ef93
commit
966be78422
8 changed files with 347 additions and 0 deletions
191
Slon/Api/V1/Polls.HC
Normal file
191
Slon/Api/V1/Polls.HC
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
U0 @slon_api_v1_async_vote_fedi(JsonObject* vote_object)
|
||||||
|
{
|
||||||
|
U8 scratch_buffer[512];
|
||||||
|
I64 this_vote_id = SysTimerRead;
|
||||||
|
|
||||||
|
JsonArray* choices = vote_object->a("choices");
|
||||||
|
JsonObject* status = vote_object->o("status");
|
||||||
|
JsonObject* ap_vote_object = NULL;
|
||||||
|
JsonObject* object = NULL;
|
||||||
|
U8* choice_name = NULL;
|
||||||
|
|
||||||
|
U8* this_actor = db->o("actors")->o(vote_object->@("username"))->@("id");
|
||||||
|
U8* remote_actor = status->o("account")->@("remote_actor");
|
||||||
|
|
||||||
|
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, slon_mem_task);
|
||||||
|
|
||||||
|
I64 i;
|
||||||
|
for (i = 0; i < choices->length; i++) {
|
||||||
|
choice_name = status->o("poll")->a("options")->o(i)->@("title");
|
||||||
|
|
||||||
|
ap_vote_object = Json.CreateObject(slon_mem_task);
|
||||||
|
ap_vote_object->set("@context", "https://www.w3.org/ns/activitystreams", JSON_STRING);
|
||||||
|
StrPrint(scratch_buffer, "%s#votes/%d/activity", this_actor, this_vote_id);
|
||||||
|
ap_vote_object->set("id", scratch_buffer, JSON_STRING);
|
||||||
|
ap_vote_object->set("to", remote_actor, JSON_STRING);
|
||||||
|
ap_vote_object->set("actor", this_actor, JSON_STRING);
|
||||||
|
ap_vote_object->set("type", "Create", JSON_STRING);
|
||||||
|
|
||||||
|
object = Json.CreateObject(slon_mem_task);
|
||||||
|
StrPrint(scratch_buffer, "%s#votes/%d", this_actor, this_vote_id);
|
||||||
|
object->set("id", scratch_buffer, JSON_STRING);
|
||||||
|
object->set("type", "Note", JSON_STRING);
|
||||||
|
object->set("name", choice_name, JSON_STRING);
|
||||||
|
object->set("attributedTo", this_actor, JSON_STRING);
|
||||||
|
object->set("to", remote_actor, JSON_STRING);
|
||||||
|
object->set("inReplyTo", status->@("uri"), JSON_STRING);
|
||||||
|
|
||||||
|
ap_vote_object->set("object", object, JSON_OBJECT);
|
||||||
|
StrPrint(scratch_buffer, "%s/inbox", remote_actor);
|
||||||
|
@slon_activitypub_signed_request(scratch_buffer, fetch_buffer, ap_vote_object);
|
||||||
|
MemSet(fetch_buffer, NULL, HTTP_FETCH_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
Free(fetch_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 @slon_api_v1_vote_fedi(U8* username, JsonObject* status, JsonArray* choices)
|
||||||
|
{
|
||||||
|
JsonObject* vote_object = Json.CreateObject(slon_mem_task);
|
||||||
|
vote_object->set("username", username, JSON_STRING);
|
||||||
|
vote_object->set("status", status, JSON_OBJECT);
|
||||||
|
vote_object->set("choices", choices, JSON_ARRAY);
|
||||||
|
Spawn(&@slon_api_v1_async_vote_fedi, vote_object, "SlonAsyncVoteTask");
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 @slon_api_v1_polls_get(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
if (session->path_count() < 4) {
|
||||||
|
session->status(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
U8* id = session->path(3);
|
||||||
|
JsonObject* status = NULL;
|
||||||
|
JsonObject* poll = NULL;
|
||||||
|
JsonArray* poll_choices = NULL;
|
||||||
|
JsonItem* poll_choice = NULL;
|
||||||
|
JsonArray* own_votes = NULL;
|
||||||
|
|
||||||
|
U8* account_id = NULL;
|
||||||
|
if (session->auth) {
|
||||||
|
account_id = session->auth->@("account_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
I64 i;
|
||||||
|
if (@slon_api_authorized(session)) {
|
||||||
|
status = @slon_api_find_status_by_poll_id(id, NULL);
|
||||||
|
if (status) {
|
||||||
|
poll = Json.Clone(status->o("poll"), session->mem_task);
|
||||||
|
poll_choices = @slon_api_status_poll_choices(session, status, account_id);
|
||||||
|
own_votes = Json.CreateArray(session->mem_task);
|
||||||
|
for (i = 0; i < poll_choices->length; i++) {
|
||||||
|
poll_choice = poll_choices->@(i, TRUE);
|
||||||
|
switch (poll_choice->type) {
|
||||||
|
case JSON_NUMBER:
|
||||||
|
own_votes->append(poll_choice->value, JSON_NUMBER);
|
||||||
|
break;
|
||||||
|
case JSON_STRING:
|
||||||
|
own_votes->append(Str2I64(poll_choice->value), JSON_NUMBER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poll->set("voted", poll_choices > NULL, JSON_BOOLEAN);
|
||||||
|
poll->set("own_votes", own_votes, JSON_ARRAY);
|
||||||
|
session->send(poll);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
session->status(404);
|
||||||
|
} else {
|
||||||
|
session->status(401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 @slon_api_v1_polls_post(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
no_warn scratch_buffer;
|
||||||
|
|
||||||
|
if (session->path_count() < 5) {
|
||||||
|
session->status(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
U8* id = session->path(3);
|
||||||
|
|
||||||
|
JsonObject* status = NULL;
|
||||||
|
JsonObject* poll = NULL;
|
||||||
|
JsonObject* return_poll = NULL;
|
||||||
|
|
||||||
|
JsonArray* choices = NULL;
|
||||||
|
JsonArray* options = NULL;
|
||||||
|
JsonItem* choice = NULL;
|
||||||
|
JsonObject* option = NULL;
|
||||||
|
JsonArray* own_votes = NULL;
|
||||||
|
|
||||||
|
JsonObject* vote = NULL;
|
||||||
|
|
||||||
|
// Still won't let us vote: iOS Masto
|
||||||
|
|
||||||
|
if (@slon_api_authorized(session)) {
|
||||||
|
SLON_AUTH_ACCOUNT_ID
|
||||||
|
|
||||||
|
status = @slon_api_find_status_by_poll_id(id, NULL);
|
||||||
|
if (!status) {
|
||||||
|
session->status(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
I64 i;
|
||||||
|
I64 choice_index = 0;
|
||||||
|
poll = status->o("poll");
|
||||||
|
choices = request_json->@("choices");
|
||||||
|
options = poll->a("options");
|
||||||
|
own_votes = Json.CreateArray(session->mem_task);
|
||||||
|
|
||||||
|
for (i = 0; i < choices->length; i++) {
|
||||||
|
choice = choices->@(i, TRUE);
|
||||||
|
switch (choice->type) {
|
||||||
|
case JSON_STRING:
|
||||||
|
choice_index = Str2I64(choice->value);
|
||||||
|
break;
|
||||||
|
case JSON_NUMBER:
|
||||||
|
choice_index = choice->value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
own_votes->append(choice_index, JSON_NUMBER);
|
||||||
|
option = options->o(choice_index);
|
||||||
|
option->set("votes_count", option->@("votes_count") + 1, JSON_NUMBER);
|
||||||
|
poll->set("votes_count", poll->@("votes_count") + 1, JSON_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@slon_db_save_status_to_disk(status);
|
||||||
|
|
||||||
|
vote = Json.CreateObject(slon_db_mem_task);
|
||||||
|
vote->set("status_id", status->@("id"), JSON_STRING);
|
||||||
|
vote->set("account_id", account_id, JSON_STRING);
|
||||||
|
vote->set("choices", Json.Clone(choices, slon_db_mem_task), JSON_ARRAY);
|
||||||
|
|
||||||
|
if (!db->o("votes")->a(account_id)) {
|
||||||
|
db->o("votes")->set(account_id, Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
|
}
|
||||||
|
db->o("votes")->a(account_id)->append(vote);
|
||||||
|
@slon_db_save_votes_to_disk;
|
||||||
|
|
||||||
|
return_poll = Json.Clone(poll, session->mem_task);
|
||||||
|
return_poll->set("voted", TRUE, JSON_BOOLEAN);
|
||||||
|
return_poll->set("own_votes", own_votes, JSON_ARRAY);
|
||||||
|
|
||||||
|
// Multiple-choice votes have to be sent in separate requests for each option? wtf
|
||||||
|
if (status->o("account")->@("remote_actor")) {
|
||||||
|
// Send votes asynchronously
|
||||||
|
@slon_api_v1_vote_fedi(@slon_api_account_by_id(account_id)->@("acct"), status, vote->a("choices"));
|
||||||
|
}
|
||||||
|
session->send(return_poll);
|
||||||
|
} else {
|
||||||
|
session->status(401);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,11 @@ U0 @slon_api_v1_statuses_query(SlonHttpSession* session, JsonArray* status_array
|
||||||
Bool exclude_reblogs = @slon_api_get_value_as_boolean(request_json->@("exclude_reblogs", TRUE));
|
Bool exclude_reblogs = @slon_api_get_value_as_boolean(request_json->@("exclude_reblogs", TRUE));
|
||||||
Bool pinned = @slon_api_get_value_as_boolean(request_json->@("pinned", TRUE));
|
Bool pinned = @slon_api_get_value_as_boolean(request_json->@("pinned", TRUE));
|
||||||
|
|
||||||
|
JsonObject* poll = NULL;
|
||||||
|
JsonArray* poll_choices = NULL;
|
||||||
|
JsonItem* poll_choice = NULL;
|
||||||
|
JsonArray* own_votes = NULL;
|
||||||
|
|
||||||
no_warn exclude_reblogs;
|
no_warn exclude_reblogs;
|
||||||
// FIXME: Implement "only_media", "exclude_reblogs", "tagged"
|
// FIXME: Implement "only_media", "exclude_reblogs", "tagged"
|
||||||
Bool exclude_status = FALSE;
|
Bool exclude_status = FALSE;
|
||||||
|
@ -71,6 +76,27 @@ U0 @slon_api_v1_statuses_query(SlonHttpSession* session, JsonArray* status_array
|
||||||
status->o("reblog")->set("reblogged", TRUE, JSON_BOOLEAN);
|
status->o("reblog")->set("reblogged", TRUE, JSON_BOOLEAN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (status->@("poll")) {
|
||||||
|
poll = status->o("poll");
|
||||||
|
poll_choices = @slon_api_status_poll_choices(session, status, account_id);
|
||||||
|
poll_choice = NULL;
|
||||||
|
own_votes = Json.CreateArray(session->mem_task);
|
||||||
|
for (i = 0; i < poll_choices->length; i++) {
|
||||||
|
poll_choice = poll_choices->@(i, TRUE);
|
||||||
|
switch (poll_choice->type) {
|
||||||
|
case JSON_NUMBER:
|
||||||
|
own_votes->append(poll_choice->value, JSON_NUMBER);
|
||||||
|
break;
|
||||||
|
case JSON_STRING:
|
||||||
|
own_votes->append(Str2I64(poll_choice->value), JSON_NUMBER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poll->set("voted", poll_choices > NULL, JSON_BOOLEAN);
|
||||||
|
poll->set("own_votes", own_votes, JSON_ARRAY);
|
||||||
|
}
|
||||||
exclude_status = FALSE;
|
exclude_status = FALSE;
|
||||||
if (status->@("deleted")) {
|
if (status->@("deleted")) {
|
||||||
exclude_status = TRUE;
|
exclude_status = TRUE;
|
||||||
|
@ -182,6 +208,11 @@ U0 @slon_api_v1_statuses_get(SlonHttpSession* session)
|
||||||
U8* id = session->path(3);
|
U8* id = session->path(3);
|
||||||
JsonObject* status = NULL;
|
JsonObject* status = NULL;
|
||||||
|
|
||||||
|
JsonObject* poll = NULL;
|
||||||
|
JsonArray* poll_choices = NULL;
|
||||||
|
JsonItem* poll_choice = NULL;
|
||||||
|
JsonArray* own_votes = NULL;
|
||||||
|
|
||||||
if (@slon_api_authorized(session)) {
|
if (@slon_api_authorized(session)) {
|
||||||
SLON_AUTH_ACCOUNT_ID
|
SLON_AUTH_ACCOUNT_ID
|
||||||
|
|
||||||
|
@ -218,6 +249,28 @@ U0 @slon_api_v1_statuses_get(SlonHttpSession* session)
|
||||||
status->o("reblog")->set("reblogged", TRUE, JSON_BOOLEAN);
|
status->o("reblog")->set("reblogged", TRUE, JSON_BOOLEAN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (status->@("poll")) {
|
||||||
|
poll = status->o("poll");
|
||||||
|
poll_choices = @slon_api_status_poll_choices(session, status, account_id);
|
||||||
|
poll_choice = NULL;
|
||||||
|
own_votes = Json.CreateArray(session->mem_task);
|
||||||
|
I64 i;
|
||||||
|
for (i = 0; i < poll_choices->length; i++) {
|
||||||
|
poll_choice = poll_choices->@(i, TRUE);
|
||||||
|
switch (poll_choice->type) {
|
||||||
|
case JSON_NUMBER:
|
||||||
|
own_votes->append(poll_choice->value, JSON_NUMBER);
|
||||||
|
break;
|
||||||
|
case JSON_STRING:
|
||||||
|
own_votes->append(Str2I64(poll_choice->value), JSON_NUMBER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poll->set("voted", poll_choices > NULL, JSON_BOOLEAN);
|
||||||
|
poll->set("own_votes", own_votes, JSON_ARRAY);
|
||||||
|
}
|
||||||
session->send(status);
|
session->send(status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
4
Slon/Endpoints/Get/Polls.HC
Normal file
4
Slon/Endpoints/Get/Polls.HC
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if (String.BeginsWith("/api/v1/polls", session->path())) {
|
||||||
|
@slon_api_v1_polls_get(session);
|
||||||
|
return;
|
||||||
|
}
|
4
Slon/Endpoints/Post/Polls.HC
Normal file
4
Slon/Endpoints/Post/Polls.HC
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if (String.BeginsWith("/api/v1/polls", session->path())) {
|
||||||
|
@slon_api_v1_polls_post(session);
|
||||||
|
return;
|
||||||
|
}
|
|
@ -681,6 +681,7 @@ U0 @slon_http_handle_get_request(SlonHttpSession* session)
|
||||||
#include "Endpoints/Get/Notifications";
|
#include "Endpoints/Get/Notifications";
|
||||||
#include "Endpoints/Get/NodeInfo";
|
#include "Endpoints/Get/NodeInfo";
|
||||||
#include "Endpoints/Get/OAuth";
|
#include "Endpoints/Get/OAuth";
|
||||||
|
#include "Endpoints/Get/Polls";
|
||||||
#include "Endpoints/Get/Search";
|
#include "Endpoints/Get/Search";
|
||||||
#include "Endpoints/Get/Statuses";
|
#include "Endpoints/Get/Statuses";
|
||||||
#include "Endpoints/Get/Suggestions";
|
#include "Endpoints/Get/Suggestions";
|
||||||
|
@ -743,6 +744,7 @@ U0 @slon_http_handle_post_request(SlonHttpSession* session)
|
||||||
#include "Endpoints/Post/Markers";
|
#include "Endpoints/Post/Markers";
|
||||||
#include "Endpoints/Post/Media";
|
#include "Endpoints/Post/Media";
|
||||||
#include "Endpoints/Post/OAuth";
|
#include "Endpoints/Post/OAuth";
|
||||||
|
#include "Endpoints/Post/Polls";
|
||||||
#include "Endpoints/Post/Statuses";
|
#include "Endpoints/Post/Statuses";
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
|
@ -22,6 +22,7 @@ WinMax(Fs);
|
||||||
#include "Api/V1/Markers";
|
#include "Api/V1/Markers";
|
||||||
#include "Api/V1/Media";
|
#include "Api/V1/Media";
|
||||||
#include "Api/V1/Notifications";
|
#include "Api/V1/Notifications";
|
||||||
|
#include "Api/V1/Polls";
|
||||||
#include "Api/V1/Statuses";
|
#include "Api/V1/Statuses";
|
||||||
#include "Api/V1/Timelines";
|
#include "Api/V1/Timelines";
|
||||||
|
|
||||||
|
|
|
@ -950,6 +950,14 @@ U0 @slon_activitypub_users_inbox(SlonHttpSession* session, U8* user)
|
||||||
JsonArray* statuses = NULL;
|
JsonArray* statuses = NULL;
|
||||||
|
|
||||||
JsonObject* status = NULL;
|
JsonObject* status = NULL;
|
||||||
|
JsonObject* poll = NULL;
|
||||||
|
|
||||||
|
JsonArray* poll_options = NULL;
|
||||||
|
JsonObject* poll_option = NULL;
|
||||||
|
I64 votes_count = 0;
|
||||||
|
|
||||||
|
JsonArray* ap_poll_options = NULL;
|
||||||
|
JsonObject* ap_poll_option = NULL;
|
||||||
|
|
||||||
JsonObject* request_object = NULL;
|
JsonObject* request_object = NULL;
|
||||||
U8* status_id = NULL;
|
U8* status_id = NULL;
|
||||||
|
@ -1101,6 +1109,39 @@ U0 @slon_activitypub_users_inbox(SlonHttpSession* session, U8* user)
|
||||||
request_object = Json.Clone(request_json, slon_mem_task);
|
request_object = Json.Clone(request_json, slon_mem_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("update", request_json->@("type"))) {
|
||||||
|
if (request_json->o("object") && !StrICmp("question", request_json->o("object")->@("type"))) {
|
||||||
|
status_id = StrFind("/", StrFind("/statuses/", request_json->o("object")->@("id")) + 1) + 1;
|
||||||
|
status = @slon_api_find_status_by_id(status_id, @slon_api_account_by_remote_actor(request_json->@("actor")));
|
||||||
|
if (status) {
|
||||||
|
// Update local copy of poll with latest vote counts
|
||||||
|
poll = status->o("poll");
|
||||||
|
poll_options = poll->a("options");
|
||||||
|
|
||||||
|
if (request_json->o("object")->a("anyOf")) {
|
||||||
|
ap_poll_options = request_json->o("object")->a("anyOf");
|
||||||
|
}
|
||||||
|
if (request_json->o("object")->a("oneOf")) {
|
||||||
|
ap_poll_options = request_json->o("object")->a("oneOf");
|
||||||
|
}
|
||||||
|
if (ap_poll_options) {
|
||||||
|
for (i = 0; i < ap_poll_options->length; i++) {
|
||||||
|
ap_poll_option = ap_poll_options->@(i);
|
||||||
|
for (j = 0; j < poll_options->length; j++) {
|
||||||
|
poll_option = poll_options->o(j);
|
||||||
|
if (!StrICmp(ap_poll_option->@("name"), poll_option->@("title"))) {
|
||||||
|
poll_option->set("votes_count", ap_poll_option->o("replies")->@("totalItems"), JSON_NUMBER);
|
||||||
|
votes_count += ap_poll_option->o("replies")->@("totalItems");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@slon_db_save_status_to_disk(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request_object = Json.Clone(request_json, slon_mem_task);
|
||||||
|
}
|
||||||
|
|
||||||
if (request_object) {
|
if (request_object) {
|
||||||
JsonObject* o = Json.CreateObject(slon_mem_task);
|
JsonObject* o = Json.CreateObject(slon_mem_task);
|
||||||
o->set("actor_for_key_id", session->actor_for_key_id, JSON_STRING);
|
o->set("actor_for_key_id", session->actor_for_key_id, JSON_STRING);
|
||||||
|
|
|
@ -179,6 +179,22 @@ JsonObject* @slon_api_status_lookup_by_in_reply_to_id(U8* id, JsonArray* statuse
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonObject* @slon_api_status_lookup_by_poll_id(U8* id, JsonArray* statuses)
|
||||||
|
{
|
||||||
|
if (!id || !statuses) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
I64 i;
|
||||||
|
JsonObject* status;
|
||||||
|
for (i = 0; i < statuses->length; i++) {
|
||||||
|
status = statuses->@(i);
|
||||||
|
if (!status->@("deleted") && status->@("poll") && !StrICmp(status->o("poll")->@("id"), id)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject* @slon_api_status_lookup_by_uri(U8* uri, JsonArray* statuses)
|
JsonObject* @slon_api_status_lookup_by_uri(U8* uri, JsonArray* statuses)
|
||||||
{
|
{
|
||||||
if (!uri || !statuses) {
|
if (!uri || !statuses) {
|
||||||
|
@ -212,6 +228,23 @@ JsonObject* @slon_api_find_status_by_id(U8* id, U8* account_id = NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonObject* @slon_api_find_status_by_poll_id(U8* id, U8* account_id = NULL)
|
||||||
|
{
|
||||||
|
if (account_id) {
|
||||||
|
return @slon_api_status_lookup_by_poll_id(id, db->o("statuses")->a(account_id));
|
||||||
|
}
|
||||||
|
JsonObject* status = NULL;
|
||||||
|
JsonKey* key = db->o("statuses")->keys;
|
||||||
|
while (key) {
|
||||||
|
status = @slon_api_status_lookup_by_poll_id(id, key->value);
|
||||||
|
if (status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
key = key->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject* @slon_api_find_status_by_uri(U8* uri, U8* account_id = NULL)
|
JsonObject* @slon_api_find_status_by_uri(U8* uri, U8* account_id = NULL)
|
||||||
{
|
{
|
||||||
if (account_id) {
|
if (account_id) {
|
||||||
|
@ -285,6 +318,24 @@ Bool @slon_api_status_is_bookmarked(SlonHttpSession* session, JsonObject* status
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonArray* @slon_api_status_poll_choices(SlonHttpSession* session, JsonObject* status, U8* account_id)
|
||||||
|
{
|
||||||
|
no_warn session;
|
||||||
|
JsonArray* votes = db->o("votes")->a(account_id);
|
||||||
|
JsonObject* vote = NULL;
|
||||||
|
if (!votes) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
I64 i;
|
||||||
|
for (i = 0; i < votes->length; i++) {
|
||||||
|
vote = votes->o(i);
|
||||||
|
if (!StrICmp(vote->@("status_id"), status->@("id")) && !StrICmp(vote->@("account_id"), account_id)) {
|
||||||
|
return vote->a("choices");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
U0 @slon_api_bookmark_status(SlonHttpSession* session, JsonObject* status, U8* account_id)
|
U0 @slon_api_bookmark_status(SlonHttpSession* session, JsonObject* status, U8* account_id)
|
||||||
{
|
{
|
||||||
Bool is_already_bookmarked = FALSE;
|
Bool is_already_bookmarked = FALSE;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue