You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
3.9 KiB
C

#include "poll.h"
#include "model/account.h"
#include "model/emoji.h"
#include "model/status.h"
#include "collections/array.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#define OBJ_TYPE struct status_poll_option
struct json_object_field status_poll_option_layout[] = {
JSON_FIELD_STRING( title, true ),
JSON_FIELD_ARRAY_OF_INTS( votes, false ),
JSON_FIELD_END,
};
#undef OBJ_TYPE
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( status_poll_option );
#define OBJ_TYPE struct status_poll
struct json_object_field status_poll_layout[] = {
JSON_FIELD_INTEGER( id, false ),
JSON_FIELD_INTEGER( votes_count, false ),
JSON_FIELD_ARRAY_OF_INTS( own_votes, false ),
JSON_FIELD_BOOL( multiple_choice, false ),
JSON_FIELD_DATETIME( expires_at, false ),
JSON_FIELD_BOOL( voted, false ),
JSON_FIELD_ARRAY_OF_TYPE( options, false, status_poll_option_type ),
JSON_FIELD_ARRAY_OF_TYPE( emoji, false, emoji_type ),
JSON_FIELD_END,
};
#undef OBJ_TYPE
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( status_poll );
void status_poll_option_free( struct status_poll_option* o )
{
if( !o ) { return; }
free(o);
}
void status_poll_free( struct status_poll* p )
{
if( !p ) { return; }
for( int i = 0; i < p->options.count; ++i ) {
status_poll_option_free( p->options.items[i] );
}
free( p->options.items );
for( int i = 0; i < p->emoji.count; ++i ) {
emoji_free( p->emoji.items[i] );
}
free( p->emoji.items );
free(p->own_votes.items);
free(p);
}
bool status_poll_has_option( struct status_poll* p, int idx )
{
if( idx < 0 ) { return false; }
return idx < p->options.count;
}
bool status_poll_add_vote( struct status* s, struct account* a, void* choices_ptr )
{
// Verify preconditions
if( !s ) { return false; }
if( !a ) { return false; }
if( !choices_ptr ) { return false; }
struct {
int* items;
int count;
} *choices = choices_ptr;
// Validate vote choices
for( int i = 0; i < choices->count; ++i ) {
if( !status_poll_has_option( s->poll, choices->items[i] ) ) {
printf( "Poll doesn't have option %d\n", choices->items[i] );
return false;
}
}
// Update model
printf( "There are %d choices in this vote\n", choices->count );
for( int i = 0; i < choices->count; ++i ) {
int choice = choices->items[i];
struct status_poll_option* option = s->poll->options.items[choice];
int id = a->id;
bool should_add = true;
if( id != poll_vote_unknown_id ) {
for( int j = 0; j < option->votes.count; ++j ) {
if( option->votes.items[j] == id ) {
printf( "Account %d has laready voted this option\n", id );
should_add = false;
break;
}
}
}
if( should_add ) {
array_append( &option->votes, sizeof(id), &id );
if( a->id == owner_account_id ) {
array_append( &s->poll->own_votes, sizeof(choice), &choice );
}
}
}
// Federate response if account is owner
if( a->id == owner_account_id ) {
s->poll->voted = true;
// https://www.w3.org/TR/activitystreams-vocabulary/#questions
// See Example 153
printf( "TODO: Create federation object\n" );
//struct ap_object* obj;
}
status_poll_update_vote_count( s->poll );
return true;
}
bool status_poll_add_vote_by_name( struct status* s, struct account* a, const char* name )
{
if( !s ) { return false; }
if( !s->poll ) { return false; }
if( !a ) { return false; }
if( !name ) { return false; }
int option_index = -1;
struct {
int* items;
int count;
} choices = {
.items = &option_index,
.count = 1,
};
for( int i = 0; i < s->poll->options.count; ++i ) {
struct status_poll_option* option = s->poll->options.items[i];
if( 0 == strcmp( option->title, name ) ) {
option_index = i;
goto have_option_index;
}
}
return false;
have_option_index:
return status_poll_add_vote( s, a, &choices );
}
void status_poll_update_vote_count( struct status_poll* poll )
{
poll->votes_count = 0;
for( int i = 0; i < poll->options.count; ++i ) {
poll->votes_count += poll->options.items[i]->votes.count;
}
}