Combine mention/follower status handling, add model support for pinned posts (not possible for posts to become pinned yet)

master
teknomunk 1 year ago
parent 46ad17fb66
commit d675a087e5

@ -53,12 +53,6 @@ void show_status_context( struct http_request* req, struct status* s )
int count;
} ancestors, replies;
status_get_context( s, &ancestors, &replies );
/*
memset( &ancestors, 0, sizeof(ancestors));
memset( &replies, 0, sizeof(replies));
struct status* test = status_from_id( 111 );
array_append( &ancestors, sizeof(test), &test );
*/
fprintf( f, "{\"ancestors\":[" );
for( int i = 0; i < ancestors.count; ++i ) {

@ -123,96 +123,6 @@ static bool route_undo_activity( struct ap_activity* act )
return false;
}
static bool route_follower_post( struct ap_activity* act )
{
// Requires an object
// TODO: if there is a ref here, fetch the object
if( act->object.tag != apaot_activity ) { return false; }
struct ap_activity* obj = act->object.ptr;
// Is this activity from a follower?
struct account* actor_account = account_from_uri( act->actor );
if( !actor_account ) {
printf( "No local data, can't be follower\n" );
return false;
}
if( !account_does_follow( actor_account, owner_account_id ) ) {
printf( "Doesn't follower owner\n" );
return false;
}
// Create local status
struct status* s = status_from_activity(obj);
status_save_new(s);
// Add to timelines
status_add_to_timeline( s, home_timeline_id );
status_add_to_timeline( s, public_timeline_id );
status_add_to_timeline( s, actor_account->id );
// TODO: create notification if user notifications are on or this is part of a watched conversation
return true;
}
static bool route_mention( struct ap_activity* act )
{
// Requires an object
if( act->object.tag != apaot_activity ) { return false; }
struct ap_activity* obj = act->object.ptr;
// Does this activity have mention me
char owner_url[512];
snprintf( owner_url, sizeof(owner_url), "https://%s/owner/actor", g_server_name );
for( int i = 0; i < obj->tags.count; ++i ) {
struct ap_activity_tag* tag = obj->tags.items[i];
printf( "tag = { &=%p, .type=%d, .href=%s, .name=%s }\n", tag, tag->type, tag->href, tag->name );
if( tag->type != aptag_mention ) { continue; }
if( 0 == strcmp(tag->href, owner_url) ) { goto does_mention; }
}
printf( "Doesn't mention, discard\n" );
return false;
does_mention:
printf( "Does mention\n" );
bool result = false;
// Get actor account
struct account* mentioner = account_from_uri( obj->actor );
if( !mentioner ) {
mentioner = account_fetch_from_uri( obj->actor );
}
// Create local status
struct status* s = status_from_activity(obj);
status_save_new(s);
// Add status to account timeline
status_add_to_timeline( s, mentioner->id );
status_add_to_timeline( s, owner_account_id );
// Create notification
struct notification* note = notification_new();
note->type = nt_mention;
note->status_id = s->id;
note->account_id = mentioner->id;
notification_save( note );
notification_free( note );
result = true;
cleanup:
account_free(mentioner);
status_free(s);
return result;
failed:
result = false;
goto cleanup;
}
static struct status* lookup_object_status( struct ap_activity* act )
{
struct status* s = NULL;
@ -263,12 +173,85 @@ static bool route_emoji_react( struct ap_activity* act )
static bool route_create( struct ap_activity* act )
{
return
route_mention(act)
|| route_follower_post(act)
;
bool result = false;
return false;
// Requires an object
// TODO: if there is a ref here, fetch the object
if( act->object.tag != apaot_activity ) { return false; }
struct ap_activity* obj = act->object.ptr;
bool mentions_me = false;
bool follows_me = false;
// Does this activity have mention me
char owner_url[512];
snprintf( owner_url, sizeof(owner_url), "https://%s/owner/actor", g_server_name );
for( int i = 0; i < obj->tags.count; ++i ) {
struct ap_activity_tag* tag = obj->tags.items[i];
//printf( "tag = { &=%p, .type=%d, .href=%s, .name=%s }\n", tag, tag->type, tag->href, tag->name );
if( tag->type != aptag_mention ) { continue; }
if( 0 == strcmp(tag->href, owner_url) ) {
mentions_me = true;
goto check_is_follower;
}
}
check_is_follower:
// Get actor account
struct account* actor_account = account_from_uri( obj->actor );
if( !actor_account ) {
actor_account = account_fetch_from_uri( obj->actor );
}
if( !actor_account ) {
printf( "! Unable to fetch %s\n", obj->actor );
goto failed;
}
if( account_does_follow( actor_account, owner_account_id ) ) {
follows_me = true;
}
if( !follows_me && !mentions_me ) {
// Discard without action
result = true;
goto cleanup;
}
// Create local status
struct status* s = status_from_activity(obj);
status_save_new(s);
// Add to timelines
if( follows_me ) {
status_add_to_timeline( s, home_timeline_id );
// TODO: create notification if user notifications are on or this is part of a watched conversation
}
if( mentions_me ) {
// Create notification
struct notification* note = notification_new();
note->type = nt_mention;
note->status_id = s->id;
note->account_id = actor_account->id;
notification_save( note );
notification_free( note );
}
// Add to standard timelines
status_add_to_timeline( s, public_timeline_id );
//status_add_to_timeline( s, federated_timeline_id );
status_add_to_timeline( s, actor_account->id );
result = true;
cleanup:
account_free(actor_account);
status_free(s);
return result;
failed:
result = false;
goto cleanup;
}
static bool route_accept( struct ap_activity* act )

@ -38,11 +38,13 @@ bool handle_timeline( struct http_request* req, int timeline_id )
int max_id;
int limit;
bool hide_muted;
bool pinned;
} params = {
.since_id = 0,
.limit = 32,
.max_id = 2147483647,
.hide_muted = true,
.pinned = false,
};
#define OBJ_TYPE struct params_t
@ -51,12 +53,12 @@ bool handle_timeline( struct http_request* req, int timeline_id )
HTTP_QUERY_FIELD_INT( limit )
HTTP_QUERY_FIELD_INT( max_id )
HTTP_QUERY_FIELD_BOOL( hide_muted )
HTTP_QUERY_FIELD_BOOL( pinned )
HTTP_QUERY_FIELD_END
};
#undef OBJ_TYPE
// handle query parameters
// TODO: split this off into a generic filter handling
if( http_request_route( req, "?" ) ) {
http_query_parse( req, fields, &params );
}
@ -82,13 +84,21 @@ bool handle_timeline( struct http_request* req, int timeline_id )
.count = 0
};
int count = timeline_load_statuses( tl, 0, params.limit, ss );
int offset = 0;
int count = 0;
int max_loops = 5;
load_statuses:
printf( "loading offset=%d,limit=%d\n", offset, params.limit );
count = timeline_load_statuses( tl, offset, params.limit, ss );
printf( "count=%d\n", count );
if( count == 0 ) { goto done; }
// Filter
for( int i = 0; i < count; ++i ) {
struct status* s = ss[i];
if( s->id <= params.since_id ) { goto filtered; }
if( s->id >= params.max_id ) { goto filtered; }
if( s->pinned != params.pinned ) { goto filtered; }
show.items[show.count] = s;
show.count += 1;
@ -98,6 +108,17 @@ bool handle_timeline( struct http_request* req, int timeline_id )
}
}
// Try to load more statuses
if( count < params.limit ) {
offset += params.limit;
params.limit -= show.count;
if( max_loops > 0 ) {
max_loops -= 1;
goto load_statuses;
}
}
done:
show_statuses( req, show.items, show.count );
for( int i = 0; i < count; ++i ) {

@ -27,8 +27,10 @@ static struct json_object_field status_layout[] = {
JSON_FIELD_BOOL( stub, false ),
JSON_FIELD_BOOL( remote, false ),
// DO NOT INCLUDE field content
JSON_FIELD_STRING( source, false ),
JSON_FIELD_BOOL( sensitive, true ),
JSON_FIELD_BOOL( pinned, false ),
JSON_FIELD_DATETIME( published, false ),
JSON_FIELD_INTEGER( in_reply_to, false ),

@ -18,6 +18,7 @@ struct status
char* content; // Deprecate from file system data and render when loading
char* source;
bool sensitive;
bool pinned;
time_t published;
int in_reply_to;

@ -85,6 +85,10 @@ void timeline_free( struct timeline* tl )
int timeline_load_statuses( struct timeline* tl, int offset_from_head, int count, struct status** result )
{
if( offset_from_head != 0 ) {
return 0;
}
// TODO: take offset_from_head into account to get starting position
if( count > tl->status_ids.count ) {
count = tl->status_ids.count;

Loading…
Cancel
Save