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')) {
7 7
 // composer
8 8
 require 'vendor/autoload.php';
9 9
 
10
+define('WEBMENTION_SERVICE', 4);
11
+
10 12
 class WebmentionsPlugin extends Plugin {
11 13
     const VERSION = '0.0.1';
12 14
 
@@ -52,15 +54,29 @@ class WebmentionsPlugin extends Plugin {
52 54
     }
53 55
 
54 56
     /**
55
-     * Ensure SQL table is proper
57
+     * Ensure 'Webmention' foreign service exists
56 58
      */
57 59
     function onCheckSchema() {
58
-        $schema = Schema::get();
59
-        $schema->ensureTable('webmentions', Webmention::schemaDef());
60
+        $foreign_service = Foreign_service::getKV('id', WEBMENTION_SERVICE);
61
+
62
+        if (!($foreign_service instanceof Foreign_service)) {
63
+            $foreign_service = new Foreign_service();
64
+
65
+            $foreign_service->id = WEBMENTION_SERVICE;
66
+            $foreign_service->name = 'Webmention';
67
+            $foreign_service->description = 'https://github.com/chimo/gs-webmentions';
68
+            $foreign_service->created = common_sql_now();
69
+
70
+            $foreign_service->insert();
71
+        }
60 72
 
61 73
         return true;
62 74
     }
63 75
 
76
+    // TODO: We'll probably need to handle StartNoticeInScope so we're allowed to
77
+    //       reply, fav, repeat notices we would otherwise not have access to.
78
+    //       https://github.com/postblue/social/blob/nightly/classes/Notice.php#L2647
79
+
64 80
     /**
65 81
      * Plugin version data
66 82
      *

+ 21
- 12
actions/webmentions.php View File

@@ -42,18 +42,27 @@ class WebmentionsAction extends ApiAction
42 42
             return true;
43 43
         }
44 44
 
45
-        $webmention = Webmention::fill($this->source, $this->target);
46
-
47
-        if ($webmention instanceof Webmention) {
48
-            if($webmention->insert()) {
49
-                // Thank you, come again
50
-                header($_SERVER['SERVER_PROTOCOL'] . ' 200 Accepted');
51
-            } else {
52
-                error_log("Could not insert webmention from " . $this->source, 4);
53
-            }
54
-
55
-        } else {
56
-            $this->clientError(_('Unknown Error'), 400);
45
+        try {
46
+            // Get webmention
47
+            // TODO: throw exception on error
48
+            $webmention = Webmention::fill($this->source, $this->target);
49
+
50
+            // Make sure foreign user exists
51
+            // TODO: throw exception on error
52
+            $foreign_user = $webmention->get_fuser();
53
+
54
+            // Make sure profile exists
55
+            // TODO: throw exception on error
56
+            $profile = $webmention->get_profile();
57
+
58
+            // Convert webmention to notice
59
+            // TODO: throw exception on error
60
+            $notice = $webmention->to_notice($profile->id);
61
+
62
+            header($_SERVER['SERVER_PROTOCOL'] . ' 200 Accepted');
63
+        } catch(Exception $e) {
64
+            error_log("WEBMENTION: caught exception", 4);
65
+            $this->clientError($e->getMessage(), 400);
57 66
         }
58 67
     }
59 68
 }

+ 104
- 71
classes/Webmention.php View File

@@ -1,76 +1,6 @@
1 1
 <?php
2 2
 
3
-class Webmention extends Managed_DataObject {
4
-    // SQL
5
-    public $__table = 'webmentions'; // table name
6
-    public $id;         // serial
7
-    public $notice_id;  // bigint unsigned not null
8
-    public $author;     // varchar(191)
9
-    public $author_url; // varchar(191)
10
-    public $title;      // varchar(191)
11
-    public $content;    // varchar(191)
12
-    public $created;    // datetime
13
-    public $remote_url; // varchar(191)
14
-    public $type;       // varchar(191)
15
-
16
-    public static function schemaDef() {
17
-        return array(
18
-            'fields' => array(
19
-                'id' => array(
20
-                    'type' => 'serial'
21
-                ),
22
-                'notice_id' => array(
23
-                    'type' => 'int',
24
-                    'size' => 'big',
25
-                    'unsigned' => true,
26
-                    'not null' => true,
27
-                ),
28
-                'author' => array(
29
-                    'type' => 'varchar',
30
-                    'length' => 191
31
-                ),
32
-                'author_url' => array(
33
-                    'type' => 'varchar',
34
-                    'length' => 191
35
-                ),
36
-                'title' => array(
37
-                    'type' => 'varchar',
38
-                    'length' => 191
39
-                ),
40
-                'content' => array(
41
-                    'type' => 'varchar',
42
-                    'length' => 191
43
-                ),
44
-                'created' => array(
45
-                    'type' => 'datetime'
46
-                ),
47
-                'remote_url' => array(
48
-                    'type' => 'varchar',
49
-                    'length' => 191
50
-                ),
51
-                'type' => array(
52
-                    'type' => 'varchar',
53
-                    'length' => 191
54
-                )
55
-            ),
56
-            'primary key' => array('id'),
57
-            'foreign keys' => array(
58
-                'notice_id_fkey' => array('notice', array('notice_id' => 'id'))
59
-            )
60
-        );
61
-    }
62
-
63
-    public function insert() {
64
-        $result = parent::insert();
65
-
66
-        if ($result === false) {
67
-            common_log_db_error($this, 'INSERT', __FILE__);
68
-            throw new ServerException('Could not save Webmention');
69
-        }
70
-
71
-        return $result;
72
-    }
73
-
3
+class Webmention {
74 4
     // TODO: Handle mentions on pages that don't use mf2
75 5
     public static function fill($sourceURL, $targetURL) {
76 6
         $wm = new Webmention();
@@ -94,6 +24,9 @@ class Webmention extends Managed_DataObject {
94 24
         $path = parse_url($targetURL, PHP_URL_PATH);
95 25
         $notice_id = basename($path);
96 26
 
27
+        // TODO: we need a way to prevent author spoofing
28
+        //   http://indiewebcamp.com/authorship#Spoofing
29
+
97 30
         // Fill $wm fields with $mf data
98 31
         $wm->notice_id = $notice_id;
99 32
         $wm->author = $mf['author']['name'];
@@ -117,6 +50,106 @@ class Webmention extends Managed_DataObject {
117 50
         return $mf;
118 51
     }
119 52
 
53
+    public function get_fuser() {
54
+        $fuser = Foreign_user::pkeyGet(array('service' => WEBMENTION_SERVICE, 'uri' => $this->author_url));
55
+
56
+        // We don't have a Foreign_user for this person. Attempt to create one.
57
+        if (!($fuser instanceof Foreign_user)) {
58
+            error_log("WEBMENTION: Couldn't find fuser, creating one...", 4);
59
+
60
+            $dataObj = new DB_DataObject();
61
+            $dataObj->query('SELECT MAX(id) as id FROM foreign_user WHERE service = ' . WEBMENTION_SERVICE);
62
+            $dataObj->fetch();
63
+            $maxId = (int)$dataObj->id + 1;
64
+
65
+            $fuser = new Foreign_user();
66
+            $fuser->id = $maxId;
67
+            $fuser->service = WEBMENTION_SERVICE;
68
+            $fuser->uri = $this->author_url;
69
+            $fuser->nickname = $this->author;
70
+            $fuser->created = common_sql_now();
71
+
72
+            if ($fuser->insert()) {
73
+                error_log("WEBMENTION: inserted new fuser");
74
+            } else {
75
+                error_log("WEBMENTION: failed to insert new fuser:");
76
+
77
+                // TODO: throw exception (?)
78
+            }
79
+        }
80
+
81
+        return $fuser;
82
+    }
83
+
84
+    public function get_profile() {
85
+        // It seems like the only relationship between Foreign_user and Profile
86
+        // is the uri -> profileurl (?)
87
+        $profile = Profile::getKV('profileurl', $this->author_url);
88
+
89
+        // We don't have a Profile for this person. Attempt to create one.
90
+        if (!($profile instanceof Profile)) {
91
+            error_log("WEBMENTION: Couldn't find profile, creating one...", 4);
92
+
93
+            $profile = new Profile();
94
+            $profile->nickname = $this->author;
95
+            $profile->fullname = $this->author;
96
+            $profile->profileurl = $this->author_url;
97
+            $profile->homepage = $this->author_url;
98
+            $profile->created = common_sql_now();
99
+            $profile->modified = common_sql_now();
100
+
101
+            if ($profile->insert()) {
102
+                error_log("WEBMENTION: inserted new profile:");
103
+                error_log(print_r($profile, true), 4);
104
+            } else {
105
+                error_log("WEBMENTION: failed to insert new profile:");
106
+                error_log(print_r($profile, true), 4);
107
+
108
+                // TODO: throw exception (?)
109
+            }
110
+        }
111
+
112
+        error_log("WEBMENTION: profile:", 4);
113
+        error_log(print_r($profile, true), 4);
114
+
115
+        return $profile;
116
+    }
117
+
118
+    public function to_notice($profile_id) {
119
+        $localNotice = Notice::getKV('id', $this->notice_id);
120
+        $conversation = $localNotice->conversation;
121
+
122
+        // TODO: convert HTML from $this->content to plain text
123
+        // TODO: check how TwitterBridge handles this
124
+        // NOTE: blindly stripping HTML tags will remove links
125
+        //       it's not a huge deal, but would be nice to keep 'em
126
+
127
+        $options = array(
128
+            'uri' => $this->remote_url,
129
+            'url' => $this->remote_url,
130
+            'created' => $this->created,
131
+            'reply_to' => $this->notice_id, // TODO: handle "likes", "repeats", etc
132
+            'object_type' => ActivityObject::COMMENT, // TODO handle "likes", "repeats", etc
133
+            'is_local' => Notice::GATEWAY,
134
+            'conversation' => $conversation
135
+
136
+            // 'repeat_of' // TODO
137
+            // 'object_type' // TODO
138
+            // 'verb' // TODO (defaults to 'post' which works with 'comment')
139
+            // 'scope' // TODO
140
+        );
141
+
142
+        $notice = new Notice();
143
+        $result = $notice->saveNew($profile_id, $this->content, 'Webmention', $options);
144
+
145
+        if (!($result instanceof Notice)) {
146
+            error_log('WEBMENTION: unable to save notice:', 4);
147
+            error_log(print_r($notice, true), 4);
148
+
149
+            // TODO: throw exception
150
+        }
151
+    }
152
+
120 153
     private function http_get($url)
121 154
     {
122 155
         $client = HTTPClient::start();

Loading…
Cancel
Save