Get account data into ap_object and remote text template for owner/actor, continue s/ap_activity/ap_object/

master
teknomunk 1 year ago
parent aca54e746f
commit ddc026cb06

@ -153,12 +153,7 @@ static bool handle_command_test( struct cli_request* req )
struct account* owner_account = account_from_id( owner_account_id );
struct ap_object* obj = account_ap_followers( owner_account );
ap_activity_write_to_FILE( obj, stdout );
printf( "\n" );
ap_object_free(obj);
obj = account_ap_followers_page( owner_account, 1 );
struct ap_object* obj = account_ap_actor( owner_account );
ap_activity_write_to_FILE( obj, stdout );
printf( "\n" );
ap_object_free(obj);

@ -320,7 +320,7 @@ failed:
goto cleanup;
}
static bool route_create( struct ap_activity* act )
static bool route_create( struct ap_object* act )
{
struct status* s = NULL;
bool result = false;
@ -332,10 +332,10 @@ static bool route_create( struct ap_activity* act )
printf( "TODO: fetch activity from %s\n", act->object.ref );
return false;
}
struct ap_activity* obj = act->object.ptr;
struct ap_object* obj = act->object.ptr;
bool mentions_me = false;
bool follows_me = false;
bool account_followed = false;
// Does this activity have mention me
char owner_url[512];
@ -368,12 +368,12 @@ check_is_follower:
owner_account = account_from_id( owner_account_id );
if( account_does_follow( owner_account, actor_account->id ) ) {
follows_me = true;
account_followed = true;
}
if( !follows_me && !mentions_me ) {
if( !account_followed && !mentions_me ) {
// Discard without action
printf( "Discarding create. follows_me=%c, mentions_me=%c\n", follows_me ? 'T' : 'F', mentions_me ? 'T' : 'F' );
//printf( "Discarding create. account_followed=%c, mentions_me=%c\n", account_followed ? 'T' : 'F', mentions_me ? 'T' : 'F' );
goto discard;
}
@ -389,7 +389,7 @@ check_is_follower:
}
// Add to timelines
if( follows_me ) {
if( account_followed ) {
status_add_to_timeline( s, home_timeline_id );
// TODO: create notification if user notifications are on or this is part of a watched conversation

@ -10,19 +10,6 @@
#include <stdio.h>
#include <string.h>
static void write_public_key( FILE* f )
{
FILE* pubkey = fopen( "data/owner/public.pem", "r" );
char ch;
while( (ch = fgetc(pubkey)) != EOF ) {
if( ch == '\n' ) {
fprintf( f, "\\n" );
} else {
fputc(ch,f);
}
}
}
static bool handle_featured( struct http_request* req )
{
struct account* owner_account = account_from_id(0);
@ -124,23 +111,12 @@ static bool handle_owner_actor( struct http_request* req )
http_request_send_headers( req, 200, "application/activity+json", true );
FILE* f = http_request_get_response_body(req);
#include "src/view/owner/actor.json.inc"
account_free( owner_account );
return true;
}
static bool show_owner_profile_page( struct http_request* req )
{
struct account* account = account_from_id(0);
const char* title = "Apogee";
http_request_send_headers( req, 200, "text/html", true );
FILE* f = http_request_get_response_body(req);
#define RENDER
#include "src/view/account_page.html.inc"
#undef RENDER
struct ap_object* obj = account_ap_actor( owner_account );
ap_activity_write_to_FILE( obj, f );
ap_object_free(obj);
account_free( owner_account );
return true;
}
@ -181,8 +157,6 @@ bool route_owner( struct http_request* req )
return handle_avatar(req);
} else if( http_request_route_term( req, "/banner.blob" ) ) {
return handle_banner(req);
} else if( http_request_route_term( req, "" ) ) {
return show_owner_profile_page(req);
}
return false;

@ -1 +1 @@
Subproject commit c8834fd690a5803ab6773045f5042e8ae53204fe
Subproject commit d1ca725373342a37aecaa56f88c463057807e613

@ -47,6 +47,21 @@ static struct json_enum account_types_enum[] = {
{ NULL },
};
#define OBJ_TYPE struct string_pair
static struct json_object_field string_pair_layout[] = {
JSON_FIELD_STRING( key, true ),
JSON_FIELD_STRING( value, true ),
JSON_FIELD_END,
};
#undef OBJ_TYPE
static struct json_field_type string_pair_type = {
.reader = json_field_object_composite_reader,
.writer = json_field_object_composite_writer,
.layout = string_pair_layout,
.size = sizeof(struct string_pair),
};
#define OBJ_TYPE struct account
static struct json_object_field account_layout[] = {
JSON_FIELD_STRING( handle, true ),
@ -85,6 +100,13 @@ static struct json_object_field account_layout[] = {
.required = false,
.type = &json_field_integer
},
{
.key = "fields",
.offset = offsetof(OBJ_TYPE, fields),
.required = false,
.type = &json_field_array_of,
.array_item_type = &string_pair_type,
},
JSON_FIELD_INTEGER( follow_activity, false ),
JSON_FIELD_STRING( account_url, true ),
JSON_FIELD_END,
@ -337,6 +359,12 @@ void account_free( struct account* a )
}
free(a->aliases.items);
for( int i = 0; i < a->fields.count; ++i ) {
free( a->fields.items[i].key );
free( a->fields.items[i].value );
}
free( a->fields.items );
free(a->note);
free(a);

@ -18,6 +18,12 @@ enum {
public_timeline_id = 2,
};
struct string_pair
{
char* key;
char* value;
};
enum account_type
{
at_owner = 1,
@ -51,6 +57,11 @@ struct account
int count;
} aliases;
struct {
struct string_pair* items;
int count;
} fields;
int followers_count;
int following_count;
int status_count;

@ -32,7 +32,52 @@ struct ap_object* account_ap_actor( struct account* a )
act = malloc(sizeof(*act));
memset(act,0,sizeof(*act));
act->published = time(NULL);
act->type = apot_person;
act->id = aformat( "https://%s/owner/actor", g_server_name );
act->name = strdup(a->display_name);
act->summary = strdup(a->note);
act->endpoints.shared_inbox = aformat("https://%s/inbox", g_server_name);
act->inbox = aformat("https://%s/inbox", g_server_name);
act->outbox = aformat("https://%s/outbox", g_server_name );
act->preferred_username = strdup(a->handle);
act->featured = aformat("https://%s/owner/collections/featured", g_server_name );
act->followers = aformat("https://%s/owner/followers", g_server_name);
act->following = aformat("https://%s/owner/following", g_server_name);
act->avatar = aformat( "https://%s/owner/avatar.blob", g_server_name );
act->banner = aformat( "https://%s/owner/banner.blob", g_server_name );
act->url = aformat( "https://%s/@%s@%s", g_server_name, a->handle, g_server_name );
act->capabilities.show = true;
struct ap_public_key* key;
key = malloc(sizeof(*key));
memset(key,0,sizeof(*key));
key->id = aformat( "https://%s/owner/actor#main-key", g_server_name );
key->owner = strdup(act->id);
FILE* f = fopen( "data/owner/public.pem", "r" );
fseek( f, 0, SEEK_END );
int size = ftell(f);
fseek( f, 0, SEEK_SET );
char* pem = malloc( size + 1 );
fread( pem, 1, size, f );
pem[size] = 0;
key->public_key = pem;
fclose(f);
act->public_key = key;
for( int i = 0; i < a->fields.count; ++i ) {
struct ap_attachment* at;
at = malloc(sizeof(*at));
memset(at,0,sizeof(*at));
at->name = strdup(a->fields.items[i].key);
at->value = strdup(a->fields.items[i].value);
at->type = apot_property_value;
array_append( &act->attachments, sizeof(at), &at );
}
return act;
}

@ -19,22 +19,36 @@
#include <stdio.h>
#include <string.h>
struct ap_activity* ap_activity_new()
struct ap_object* ap_activity_new()
{
struct ap_activity* act = malloc(sizeof(struct ap_activity));
memset(act,0,sizeof(struct ap_activity));
struct ap_object* act;
act = malloc(sizeof(*act));
memset(act,0,sizeof(*act));
return act;
}
struct ap_activity* ap_activity_dup( struct ap_activity* act )
struct ap_object* ap_activity_dup( struct ap_object* act )
{
struct ap_activity* new_act = ap_activity_new();
struct ap_object* new_act = ap_activity_new();
memset(new_act,0,sizeof(*new_act));
new_act->id = strdup(act->id);
new_act->id = safe_strdup(act->id);
new_act->actor = safe_strdup(act->actor);
new_act->name = safe_strdup(act->name);
new_act->local_id = act->local_id;
new_act->type = act->type;
new_act->actor = strdup(act->actor);
new_act->inbox = safe_strdup(act->inbox);
new_act->outbox = safe_strdup(act->outbox);
new_act->preferred_username = safe_strdup(act->preferred_username);
new_act->url = safe_strdup(act->url);
new_act->endpoints.shared_inbox = safe_strdup(act->endpoints.shared_inbox);
new_act->featured = safe_strdup(act->featured);
new_act->followers = safe_strdup(act->followers);
new_act->following = safe_strdup(act->following);
new_act->avatar = safe_strdup(act->avatar);
new_act->banner = safe_strdup(act->banner);
new_act->attributed_to = safe_strdup(act->attributed_to);
new_act->published = act->published;
@ -63,8 +77,8 @@ struct ap_activity* ap_activity_dup( struct ap_activity* act )
array_append( &new_act->tags, sizeof(new_tag), &new_tag );
}
for( int i = 0; i < act->attachments.count; ++i ) {
struct ap_attachement* old_att = act->attachments.items[i];
struct ap_attachement* new_att;
struct ap_attachment* old_att = act->attachments.items[i];
struct ap_attachment* new_att;
new_att = malloc(sizeof(*new_att));
memset(new_att,0,sizeof(*new_att));
@ -114,6 +128,7 @@ struct ap_activity* ap_activity_dup( struct ap_activity* act )
return new_act;
}
void ap_public_key_free( struct ap_public_key* pk );
void ap_object_free( struct ap_activity* act )
{
if( !act ) { return; }
@ -124,6 +139,19 @@ void ap_activity_free_composite( struct ap_activity* act )
{
free(act->id);
free(act->actor);
free(act->name);
free(act->inbox);
free(act->outbox);
free(act->preferred_username);
free(act->url);
free(act->endpoints.shared_inbox);
free(act->featured);
free(act->followers);
free(act->following);
free(act->avatar);
free(act->banner);
ap_public_key_free( act->public_key );
free(act->context);
for( int i = 0; i < act->ap_context.extra.count; ++i ) {
@ -148,7 +176,7 @@ void ap_activity_free_composite( struct ap_activity* act )
free(act->tags.items);
for( int i = 0; i < act->attachments.count; ++i ) {
ap_attachement_free( act->attachments.items[i] );
ap_attachment_free( act->attachments.items[i] );
}
free( act->attachments.items );
@ -419,7 +447,7 @@ struct ap_activity* ap_activity_create_note( struct status* s )
for( int i = 0; i < s->media.count; ++i ) {
struct media* m = media_from_local_uri( s->media.items[i] );
if( m ) {
struct ap_attachement* att;
struct ap_attachment* att;
att = malloc(sizeof(*att));
memset(att,0,sizeof(*att));

@ -92,6 +92,9 @@ enum ap_object_type
apot_ordered_collection_page = 302,
apot_collection = 303,
apot_collection_page = 304,
// Other
apot_property_value = 401,
};
extern struct json_enum ap_object_type_enum[];
@ -101,7 +104,7 @@ enum ap_activity_object_type {
apaot_object = 2,
};
struct ap_attachement
struct ap_attachment
{
int type;
char* mediaType;
@ -109,8 +112,8 @@ struct ap_attachement
char* url;
char* value;
};
void ap_attachement_free( struct ap_attachement* a );
extern struct json_field_type ap_attachement_type;
void ap_attachment_free( struct ap_attachment* a );
extern struct json_field_type ap_attachment_type;
struct ap_object_ptr_or_ref
{
@ -120,6 +123,12 @@ struct ap_object_ptr_or_ref
struct ap_object* ptr;
};
};
struct ap_public_key
{
char* id;
char* owner;
char* public_key;
};
void ap_object_ptr_or_ref_free( struct ap_object_ptr_or_ref* oor );
void ap_object_ptr_or_ref_free_composite( struct ap_object_ptr_or_ref* oor );
@ -129,9 +138,31 @@ struct ap_object
char* id;
char* actor;
char* name;
int local_id;
int type;
// Actor-specific fields
char* inbox;
char* outbox;
char* preferred_username;
char* url;
struct {
char* shared_inbox;
} endpoints;
char* featured;
char* followers;
char* following;
struct {
bool show;
bool accepts_chat_messages;
} capabilities;
char* avatar;
char* banner;
bool discoverable;
bool manually_approves_followers;
struct ap_public_key* public_key;
char* context;
int context_id;
@ -157,7 +188,7 @@ struct ap_object
} tags;
struct {
struct ap_attachement** items;
struct ap_attachment** items;
int count;
} attachments;

@ -5,8 +5,8 @@
extern struct json_enum ap_object_type_enum[];
#define OBJ_TYPE struct ap_attachement
struct json_object_field ap_attachement_layout[] = {
#define OBJ_TYPE struct ap_attachment
struct json_object_field ap_attachment_layout[] = {
JSON_FIELD_STRING( mediaType, false ),
JSON_FIELD_STRING( name, false ),
JSON_FIELD_STRING( value, false ),
@ -15,7 +15,7 @@ struct json_object_field ap_attachement_layout[] = {
JSON_FIELD_END
};
#undef OBJ_TYPE
void ap_attachement_free( struct ap_attachement* a )
void ap_attachment_free( struct ap_attachment* a )
{
if( !a ) { return; }
@ -25,5 +25,5 @@ void ap_attachement_free( struct ap_attachement* a )
free(a->value);
free(a);
}
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( ap_attachement );
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( ap_attachment );

@ -39,20 +39,26 @@ struct json_enum ap_object_type_enum[] = {
{ "Block", apat_block },
{ "Flag", apat_flag },
{ "Dislike", apat_dislike },
{ "Question", apat_question },
{ "EmojiReact", apat_emoji_react },
{ "Note", apat_note },
{ "Person", apat_person },
{ "Service", apot_service },
{ "Question", apat_question },
{ "Document", apot_document },
{ "Image", apot_image },
{ "Tombstone", apot_tombstone },
{ "Person", apat_person },
{ "Service", apot_service },
{ "Application", apot_application },
{ "Group", apot_group },
{ "Organization", apot_organization },
{ "Collection", apot_collection },
{ "CollectionPage", apot_collection_page },
{ "OrderedCollection", apot_ordered_collection },
{ "OrderedCollectionPage", apot_ordered_collection_page },
{ "Tombstone", apot_tombstone },
{ "PropertyValue", apot_property_value },
{ NULL, 0 },
};
@ -66,6 +72,37 @@ struct json_tagged_union_typelist signature_types[] = {
JSON_TAGGED_UNION_TYPELIST_END,
};
extern struct json_field_type endpoints_type;
extern struct json_field_type image_type;
extern struct json_field_type capabilities_type;
#define OBJ_TYPE struct ap_public_key
static struct json_object_field ap_public_key_layout[] = {
JSON_FIELD_STRING( id, true ),
JSON_FIELD_STRING( owner, true ),
{
.key = "publicKeyPem",
.offset = offsetof( OBJ_TYPE, public_key ),
.required = true,
.type = &json_field_string,
},
JSON_FIELD_END,
};
#undef OBJ_TYPE
void ap_public_key_free( struct ap_public_key* pk )
{
if( !pk ) { return; }
free( pk->id );
free( pk->owner );
free( pk->public_key );
free( pk );
}
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( ap_public_key );
#define OBJ_TYPE struct ap_object
struct json_object_field ap_object_layout[] = {
{
@ -77,8 +114,59 @@ struct json_object_field ap_object_layout[] = {
JSON_FIELD_STRING(id,false),
JSON_FIELD_STRING(actor,false),
JSON_FIELD_STRING(name,false),
JSON_FIELD_STRING(state,false),
JSON_FIELD_STRING(inbox,false),
JSON_FIELD_STRING(outbox,false),
{
.key = "preferredUsername",
.offset = offsetof( OBJ_TYPE, preferred_username ),
.required = false,
.type = &json_field_string,
},
JSON_FIELD_STRING(url,false),
{
.key = "endpoints",
.offset = 0,
.required = false,
.type = &endpoints_type,
},
JSON_FIELD_STRING( featured, false ),
JSON_FIELD_STRING( following, false ),
JSON_FIELD_STRING( followers, false ),
{
.key = "icon",
.offset = offsetof( OBJ_TYPE, avatar ),
.required = false,
.type = &image_type,
},
{
.key = "image",
.offset = offsetof( OBJ_TYPE, banner ),
.required = false,
.type = &image_type,
},
{
.key = "capabilities",
.offset = 0,
.required = false,
.type = &capabilities_type,
},
JSON_FIELD_BOOL( discoverable, false ),
{
.key = "manuallyApprovesFollowers",
.offset = offsetof( OBJ_TYPE, manually_approves_followers ),
.required = false,
.type = &json_field_bool,
},
{
.key = "publicKey",
.offset = offsetof( OBJ_TYPE, public_key ),
.required = false,
.type = &ap_public_key_type,
},
{
.key = "content",
.offset = offsetof( OBJ_TYPE, content ),
@ -146,9 +234,10 @@ struct json_object_field ap_object_layout[] = {
.required = false,
.allow_drop_empty_array = true,
.type = &json_field_array_of,
.array_item_type = &ap_attachement_type
.array_item_type = &ap_attachment_type
},
{
.key = "to",
.offset = offsetof( OBJ_TYPE, to ),

@ -0,0 +1,37 @@
#include "model/ap/activity.h"
#define OBJ_TYPE struct ap_object
static struct json_object_field capabilities_layout[] = {
{
.key = "acceptsChatMessages",
.offset = offsetof( OBJ_TYPE, capabilities.accepts_chat_messages ),
.required = false,
.always_write = true,
.type = &json_field_bool,
},
JSON_FIELD_END,
};
#undef OBJ_TYPE
static bool capabilities_reader( struct json_pull_parser* jpp, void* field_data, struct json_object_field* layout_field_data )
{
struct ap_object* o = field_data;
o->capabilities.show = true;
return json_read_object_layout( jpp, capabilities_layout, field_data );
}
static bool capabilities_writer( struct json_writer* jw, const char* field_name, void* field_data, struct json_object_field* layout_field_data )
{
struct ap_object* o = field_data;
if( !o->capabilities.show ) { return false; }
write:
json_write_field_name(jw,field_name);
json_write_pretty_object_layout( jw, capabilities_layout, field_data );
return true;
}
struct json_field_type capabilities_type = {
.reader = capabilities_reader,
.writer = capabilities_writer,
.layout = capabilities_layout,
};

@ -0,0 +1,30 @@
#include "model/ap/activity.h"
#define OBJ_TYPE struct ap_object
static struct json_object_field endpoints_layout[] = {
{
.key = "sharedInbox",
.offset = offsetof( OBJ_TYPE, endpoints.shared_inbox ),
.required = false,
.type = &json_field_string,
},
JSON_FIELD_END,
};
#undef OBJ_TYPE
static bool endpoints_writer( struct json_writer* jw, const char* field_name, void* field_data, struct json_object_field* layout_field_data )
{
struct ap_object* o = field_data;
if( o->endpoints.shared_inbox ) { goto write; }
return false;
write:
json_write_field_name(jw,field_name);
json_write_pretty_object_layout( jw, endpoints_layout, o );
return true;
}
struct json_field_type endpoints_type = {
.reader = json_field_object_composite_reader,
.writer = endpoints_writer,
.layout = endpoints_layout,
};

@ -0,0 +1,30 @@
#include "model/ap/activity.h"
#define OBJ_TYPE struct ap_object
static struct json_object_field image_layout[] = {
JSON_FIELD_FIXED_STRING( type, "Image", true ),
{
.key = "url",
.offset = 0,
.required = true,
.type = &json_field_string,
},
JSON_FIELD_END,
};
#undef OBJ_TYPE
bool image_writer( struct json_writer* jw, const char* field_name, void* field_data, struct json_object_field* layout_field_data )
{
char** avatar = field_data;
if( !*avatar ) { return false; }
write:
json_write_field_name(jw,field_name);
json_write_pretty_object_layout( jw, image_layout, avatar );
return true;
}
struct json_field_type image_type = {
.reader = json_field_object_composite_reader,
.writer = image_writer,
.layout = image_layout,
};

@ -276,7 +276,7 @@ bool status_sync_from_activity_pub( struct status* s, struct ap_activity* act )
// Recreate the media field
for( int i = 0; i < act->attachments.count; ++i ) {
struct ap_attachement* att = act->attachments.items[i];
struct ap_attachment* att = act->attachments.items[i];
if( att && att->url ) {
char* media = strdup( att->url );
array_append( &s->media, sizeof(char*), &media );
@ -450,7 +450,7 @@ struct status* status_new_system_stub( struct status* stub )
return s;
}
struct status* status_from_activity( struct ap_activity* act )
struct status* status_from_activity( struct ap_object* act )
{
struct status* s;
s = malloc(sizeof(*s));

@ -1,3 +0,0 @@
%( view_begin_layout(f,title); )
<h1>%s{ account->display_name }</h1>
%( view_end_layout(f); )

@ -1,53 +0,0 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{"@language":"und"}
],
"alsoKnownAs":[],
"attachment":[
{
"name":"blog",
"type":"PropertyValue",
"value":"<a href=\"http://blog.polaris-1.work\" rel=\"ugc\">blog.polaris-1.work</a>"
},
{
"name":"git repo",
"type":"PropertyValue",
"value":"<a href=\"https://gitea.polaris-1.work/\" rel=\"ugc\">https://gitea.polaris-1.work/</a>"
}
],
"capabilities":{
"acceptsChatMessages":false
},
"discoverable":false,
"endpoints":{
"sharedInbox":"https://%s{g_server_name}/inbox"
},
"featured":"https://%s{g_server_name}/owner/collections/featured",
"followers":"https://%s{g_server_name}/owner/followers",
"following":"https://%s{g_server_name}/owner/following",
"icon":{
"type":"Image",
"url":"https://pl.polaris-1.work/media/167d2f4b1176e30dffcfe29b25faddd5a2336d3c1b2baf2bc337101e29f7d48f.blob"
},
"id": "https://%s{g_server_name}/owner/actor",
"image":{
"type":"Image",
"url":"https://pl.polaris-1.work/media/8374fc3fece3646babd9d160e5f0b41231950b706f51de964e9dfb77157c7f6b.png"
},
"inbox":"https://%s{g_server_name}/inbox",
"manuallyApprovesFollowers":false,
"name":"%s{owner_account->display_name}",
"outbox":"https://%s{g_server_name}/outbox",
"preferredUsername":"%s{owner_account->handle}",
"publicKey":{
"id":"https://%s{g_server_name}/owner/actor#main-key",
"owner":"https://%s{g_server_name}/owner/actor",
"publicKeyPem":"%( write_public_key(f); )"
},
"summary":"",
"tag":[
],
"type":"Person",
"url":"https://%s{g_server_name}/owner"
}
Loading…
Cancel
Save