Browse Source

Some work on GS integration (#3)

Notice is here: http://sn.chromic.org/notice/824931
It's a reply part of this conversation:
http://sn.chromic.org/conversation/817628
master
Chimo 4 years ago
parent
commit
f1d95db143
3 changed files with 144 additions and 86 deletions
  1. 19
    3
      WebmentionsPlugin.php
  2. 21
    12
      actions/webmentions.php
  3. 104
    71
      classes/Webmention.php

+ 19
- 3
WebmentionsPlugin.php View File

@@ -7,6 +7,8 @@ if (!defined('GNUSOCIAL')) {
// composer
require 'vendor/autoload.php';

define('WEBMENTION_SERVICE', 4);

class WebmentionsPlugin extends Plugin {
const VERSION = '0.0.1';

@@ -52,15 +54,29 @@ class WebmentionsPlugin extends Plugin {
}

/**
* Ensure SQL table is proper
* Ensure 'Webmention' foreign service exists
*/
function onCheckSchema() {
$schema = Schema::get();
$schema->ensureTable('webmentions', Webmention::schemaDef());
$foreign_service = Foreign_service::getKV('id', WEBMENTION_SERVICE);

if (!($foreign_service instanceof Foreign_service)) {
$foreign_service = new Foreign_service();

$foreign_service->id = WEBMENTION_SERVICE;
$foreign_service->name = 'Webmention';
$foreign_service->description = 'https://github.com/chimo/gs-webmentions';
$foreign_service->created = common_sql_now();

$foreign_service->insert();
}

return true;
}

// TODO: We'll probably need to handle StartNoticeInScope so we're allowed to
// reply, fav, repeat notices we would otherwise not have access to.
// https://github.com/postblue/social/blob/nightly/classes/Notice.php#L2647

/**
* Plugin version data
*

+ 21
- 12
actions/webmentions.php View File

@@ -42,18 +42,27 @@ class WebmentionsAction extends ApiAction
return true;
}

$webmention = Webmention::fill($this->source, $this->target);

if ($webmention instanceof Webmention) {
if($webmention->insert()) {
// Thank you, come again
header($_SERVER['SERVER_PROTOCOL'] . ' 200 Accepted');
} else {
error_log("Could not insert webmention from " . $this->source, 4);
}

} else {
$this->clientError(_('Unknown Error'), 400);
try {
// Get webmention
// TODO: throw exception on error
$webmention = Webmention::fill($this->source, $this->target);

// Make sure foreign user exists
// TODO: throw exception on error
$foreign_user = $webmention->get_fuser();

// Make sure profile exists
// TODO: throw exception on error
$profile = $webmention->get_profile();

// Convert webmention to notice
// TODO: throw exception on error
$notice = $webmention->to_notice($profile->id);

header($_SERVER['SERVER_PROTOCOL'] . ' 200 Accepted');
} catch(Exception $e) {
error_log("WEBMENTION: caught exception", 4);
$this->clientError($e->getMessage(), 400);
}
}
}

+ 104
- 71
classes/Webmention.php View File

@@ -1,76 +1,6 @@
<?php

class Webmention extends Managed_DataObject {
// SQL
public $__table = 'webmentions'; // table name
public $id; // serial
public $notice_id; // bigint unsigned not null
public $author; // varchar(191)
public $author_url; // varchar(191)
public $title; // varchar(191)
public $content; // varchar(191)
public $created; // datetime
public $remote_url; // varchar(191)
public $type; // varchar(191)

public static function schemaDef() {
return array(
'fields' => array(
'id' => array(
'type' => 'serial'
),
'notice_id' => array(
'type' => 'int',
'size' => 'big',
'unsigned' => true,
'not null' => true,
),
'author' => array(
'type' => 'varchar',
'length' => 191
),
'author_url' => array(
'type' => 'varchar',
'length' => 191
),
'title' => array(
'type' => 'varchar',
'length' => 191
),
'content' => array(
'type' => 'varchar',
'length' => 191
),
'created' => array(
'type' => 'datetime'
),
'remote_url' => array(
'type' => 'varchar',
'length' => 191
),
'type' => array(
'type' => 'varchar',
'length' => 191
)
),
'primary key' => array('id'),
'foreign keys' => array(
'notice_id_fkey' => array('notice', array('notice_id' => 'id'))
)
);
}

public function insert() {
$result = parent::insert();

if ($result === false) {
common_log_db_error($this, 'INSERT', __FILE__);
throw new ServerException('Could not save Webmention');
}

return $result;
}

class Webmention {
// TODO: Handle mentions on pages that don't use mf2
public static function fill($sourceURL, $targetURL) {
$wm = new Webmention();
@@ -94,6 +24,9 @@ class Webmention extends Managed_DataObject {
$path = parse_url($targetURL, PHP_URL_PATH);
$notice_id = basename($path);

// TODO: we need a way to prevent author spoofing
// http://indiewebcamp.com/authorship#Spoofing

// Fill $wm fields with $mf data
$wm->notice_id = $notice_id;
$wm->author = $mf['author']['name'];
@@ -117,6 +50,106 @@ class Webmention extends Managed_DataObject {
return $mf;
}

public function get_fuser() {
$fuser = Foreign_user::pkeyGet(array('service' => WEBMENTION_SERVICE, 'uri' => $this->author_url));

// We don't have a Foreign_user for this person. Attempt to create one.
if (!($fuser instanceof Foreign_user)) {
error_log("WEBMENTION: Couldn't find fuser, creating one...", 4);

$dataObj = new DB_DataObject();
$dataObj->query('SELECT MAX(id) as id FROM foreign_user WHERE service = ' . WEBMENTION_SERVICE);
$dataObj->fetch();
$maxId = (int)$dataObj->id + 1;

$fuser = new Foreign_user();
$fuser->id = $maxId;
$fuser->service = WEBMENTION_SERVICE;
$fuser->uri = $this->author_url;
$fuser->nickname = $this->author;
$fuser->created = common_sql_now();

if ($fuser->insert()) {
error_log("WEBMENTION: inserted new fuser");
} else {
error_log("WEBMENTION: failed to insert new fuser:");

// TODO: throw exception (?)
}
}

return $fuser;
}

public function get_profile() {
// It seems like the only relationship between Foreign_user and Profile
// is the uri -> profileurl (?)
$profile = Profile::getKV('profileurl', $this->author_url);

// We don't have a Profile for this person. Attempt to create one.
if (!($profile instanceof Profile)) {
error_log("WEBMENTION: Couldn't find profile, creating one...", 4);

$profile = new Profile();
$profile->nickname = $this->author;
$profile->fullname = $this->author;
$profile->profileurl = $this->author_url;
$profile->homepage = $this->author_url;
$profile->created = common_sql_now();
$profile->modified = common_sql_now();

if ($profile->insert()) {
error_log("WEBMENTION: inserted new profile:");
error_log(print_r($profile, true), 4);
} else {
error_log("WEBMENTION: failed to insert new profile:");
error_log(print_r($profile, true), 4);

// TODO: throw exception (?)
}
}

error_log("WEBMENTION: profile:", 4);
error_log(print_r($profile, true), 4);

return $profile;
}

public function to_notice($profile_id) {
$localNotice = Notice::getKV('id', $this->notice_id);
$conversation = $localNotice->conversation;

// TODO: convert HTML from $this->content to plain text
// TODO: check how TwitterBridge handles this
// NOTE: blindly stripping HTML tags will remove links
// it's not a huge deal, but would be nice to keep 'em

$options = array(
'uri' => $this->remote_url,
'url' => $this->remote_url,
'created' => $this->created,
'reply_to' => $this->notice_id, // TODO: handle "likes", "repeats", etc
'object_type' => ActivityObject::COMMENT, // TODO handle "likes", "repeats", etc
'is_local' => Notice::GATEWAY,
'conversation' => $conversation

// 'repeat_of' // TODO
// 'object_type' // TODO
// 'verb' // TODO (defaults to 'post' which works with 'comment')
// 'scope' // TODO
);

$notice = new Notice();
$result = $notice->saveNew($profile_id, $this->content, 'Webmention', $options);

if (!($result instanceof Notice)) {
error_log('WEBMENTION: unable to save notice:', 4);
error_log(print_r($notice, true), 4);

// TODO: throw exception
}
}

private function http_get($url)
{
$client = HTTPClient::start();

Loading…
Cancel
Save