Merge branch 'at-mention-url' into 'master'
MentionURL Plugin This plugin enables users to use the syntax `@twitter.com/singpolyma` to mention users the system does not know about, or to be more specific when a nickname is ambiguous. See merge request !53
This commit is contained in:
		@@ -648,7 +648,7 @@ function common_linkify_mentions($text, Notice $notice)
 | 
			
		||||
 | 
			
		||||
        $linkText = common_linkify_mention($mention);
 | 
			
		||||
 | 
			
		||||
        $text = substr_replace($text, $linkText, $position, mb_strlen($mention['text']));
 | 
			
		||||
        $text = substr_replace($text, $linkText, $position, $mention['length']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $text;
 | 
			
		||||
@@ -765,6 +765,7 @@ function common_find_mentions($text, Notice $notice)
 | 
			
		||||
                                 'type' => 'mention',
 | 
			
		||||
                                 'text' => $match[0],
 | 
			
		||||
                                 'position' => $match[1],
 | 
			
		||||
                                 'length' => mb_strlen($match[0]),
 | 
			
		||||
                                 'url' => $url);
 | 
			
		||||
 | 
			
		||||
                if (!empty($mentioned->fullname)) {
 | 
			
		||||
@@ -795,6 +796,7 @@ function common_find_mentions($text, Notice $notice)
 | 
			
		||||
                                'type'      => 'list',
 | 
			
		||||
                                'text' => $hmatch[0],
 | 
			
		||||
                                'position' => $hmatch[1],
 | 
			
		||||
                                'length' => mb_strlen($hmatch[0]),
 | 
			
		||||
                                'url' => $url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -814,6 +816,7 @@ function common_find_mentions($text, Notice $notice)
 | 
			
		||||
                                'type'      => 'group',
 | 
			
		||||
                                'text'      => $hmatch[0],
 | 
			
		||||
                                'position'  => $hmatch[1],
 | 
			
		||||
                                'length'    => mb_strlen($hmatch[0]),
 | 
			
		||||
                                'url'       => $group->permalink(),
 | 
			
		||||
                                'title'     => $group->getFancyName());
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										84
									
								
								plugins/MentionURL/MentionURLPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								plugins/MentionURL/MentionURLPlugin.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
if (!defined('GNUSOCIAL')) { exit(1); }
 | 
			
		||||
 | 
			
		||||
require_once __DIR__ . '/lib/util.php';
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This plugin lets you type @twitter.com/singpolyma
 | 
			
		||||
 * so that you can be specific instead of relying on heuristics.
 | 
			
		||||
 */
 | 
			
		||||
class MentionURLPlugin extends Plugin
 | 
			
		||||
{
 | 
			
		||||
    function onEndFindMentions(Profile $sender, $text, &$mentions)
 | 
			
		||||
    {
 | 
			
		||||
        $matches = array();
 | 
			
		||||
 | 
			
		||||
        preg_match_all('/(?:^|\s+)@([A-Za-z0-9_:\-\.\/%]+)\b/',
 | 
			
		||||
                       $text,
 | 
			
		||||
                       $atmatches,
 | 
			
		||||
                       PREG_OFFSET_CAPTURE);
 | 
			
		||||
 | 
			
		||||
        foreach ($atmatches[1] as $match) {
 | 
			
		||||
            $url = $match[0];
 | 
			
		||||
            if(!common_valid_http_url($url)) { $url = 'http://' . $url; }
 | 
			
		||||
            if(common_valid_http_url($url)) {
 | 
			
		||||
                $mentioned = Mention_url_profile::fromUrl($url);
 | 
			
		||||
                $text = mb_strlen($mentioned->nickname) <= mb_strlen($match[0]) ? $mentioned->nickname : $match[0];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if($mentioned instanceof Profile) {
 | 
			
		||||
                $matches[$match[1]] = array('mentioned' => array($mentioned),
 | 
			
		||||
                                            'type' => 'mention',
 | 
			
		||||
                                            'text' => $text,
 | 
			
		||||
                                            'position' => $match[1],
 | 
			
		||||
                                            'length' => mb_strlen($match[0]),
 | 
			
		||||
                                            'url' => $mentioned->profileurl);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($mentions as $i => $other) {
 | 
			
		||||
            // If we share a common prefix with a local user, override it!
 | 
			
		||||
            $pos = $other['position'];
 | 
			
		||||
            if (isset($matches[$pos])) {
 | 
			
		||||
                $mentions[$i] = $matches[$pos];
 | 
			
		||||
                unset($matches[$pos]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        foreach ($matches as $mention) {
 | 
			
		||||
            $mentions[] = $mention;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function onStartGetProfileFromURI($uri, &$profile)
 | 
			
		||||
    {
 | 
			
		||||
        $mention_profile = Mention_url_profile::getKV('profileurl', $uri);
 | 
			
		||||
        if($mention_profile instanceof Mention_url_profile) {
 | 
			
		||||
            $profile = $mention_profile->getProfile();
 | 
			
		||||
            return !($profile instanceof Profile);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function onCheckSchema()
 | 
			
		||||
    {
 | 
			
		||||
        $schema = Schema::get();
 | 
			
		||||
        $schema->ensureTable('mention_url_profile', Mention_url_profile::schemaDef());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function onPluginVersion(array &$versions)
 | 
			
		||||
    {
 | 
			
		||||
        $versions[] = array('name' => 'MentionURL',
 | 
			
		||||
                            'version' => GNUSOCIAL_VERSION,
 | 
			
		||||
                            'author' => 'Stephen Paul Weber',
 | 
			
		||||
                            'homepage' => 'http://gnu.io/',
 | 
			
		||||
                            'description' =>
 | 
			
		||||
                            // TRANS: Plugin description.
 | 
			
		||||
                            _m('Plugin to allow mentioning arbitrary URLs.'));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										118
									
								
								plugins/MentionURL/classes/Mention_url_profile.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								plugins/MentionURL/classes/Mention_url_profile.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.     If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('GNUSOCIAL')) { exit(1); }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Table Definition for mention_url_profile
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class Mention_url_profile extends Managed_DataObject
 | 
			
		||||
{
 | 
			
		||||
    public $__table = 'mention_url_profile'; // table name
 | 
			
		||||
    public $profile_id;                      // int(4) not_null
 | 
			
		||||
    public $profileurl;                      // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
 | 
			
		||||
 | 
			
		||||
    public static function schemaDef()
 | 
			
		||||
    {
 | 
			
		||||
        return array(
 | 
			
		||||
            'fields' => array(
 | 
			
		||||
                'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'matches exactly one profile id'),
 | 
			
		||||
                'profileurl' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'URL of the profile'),
 | 
			
		||||
            ),
 | 
			
		||||
            'primary key' => array('profileurl'),
 | 
			
		||||
            'foreign keys' => array(
 | 
			
		||||
                'mention_url_profile_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function fromUrl($url, $depth=0) {
 | 
			
		||||
        common_debug('MentionURL: trying to find a profile for ' . $url);
 | 
			
		||||
 | 
			
		||||
        $url = preg_replace('#https?://#', 'https://', $url);
 | 
			
		||||
        try {
 | 
			
		||||
            $profile = Profile::fromUri($url);
 | 
			
		||||
        } catch(UnknownUriException $ex) {}
 | 
			
		||||
 | 
			
		||||
        if(!($profile instanceof Profile)) {
 | 
			
		||||
            $profile = self::findProfileByProfileURL($url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $url = str_replace('https://', 'http://', $url);
 | 
			
		||||
        if(!($profile instanceof Profile)) {
 | 
			
		||||
            try {
 | 
			
		||||
                $profile = Profile::fromUri($url);
 | 
			
		||||
            } catch(UnknownUriException $ex) {}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!($profile instanceof Profile)) {
 | 
			
		||||
            $profile = self::findProfileByProfileURL($url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!($profile instanceof Profile)) {
 | 
			
		||||
            $hcard = mention_url_representative_hcard($url);
 | 
			
		||||
            if(!$hcard) return null;
 | 
			
		||||
 | 
			
		||||
            $mention_profile = new Mention_url_profile();
 | 
			
		||||
            $mention_profile->query('BEGIN');
 | 
			
		||||
 | 
			
		||||
            $profile = new Profile();
 | 
			
		||||
            $profile->profileurl = $hcard['url'][0];
 | 
			
		||||
            $profile->fullname = $hcard['name'][0];
 | 
			
		||||
            preg_match('/\/([^\/]+)\/*$/', $profile->profileurl, $matches);
 | 
			
		||||
            if(!$hcard['nickname']) $hcard['nickname'] = array($matches[1]);
 | 
			
		||||
            $profile->nickname = $hcard['nickname'][0];
 | 
			
		||||
            $profile->created = common_sql_now();
 | 
			
		||||
 | 
			
		||||
            $mention_profile->profile_id = $profile->insert();
 | 
			
		||||
            if(!$mention_profile->profile_id) {
 | 
			
		||||
                $mention_profile->query('ROLLBACK');
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $mention_profile->profileurl = $profile->profileurl;
 | 
			
		||||
            if(!$mention_profile->insert()) {
 | 
			
		||||
                $mention_profile->query('ROLLBACK');
 | 
			
		||||
                if($depth > 0) {
 | 
			
		||||
                    return null;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return self::fromUrl($url, $depth+1);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                $mention_profile->query('COMMIT');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $profile;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static function findProfileByProfileURL($url) {
 | 
			
		||||
        $profile = Profile::getKV('profileurl', $url);
 | 
			
		||||
        if($profile instanceof Profile) {
 | 
			
		||||
            $mention_profile = new Mention_url_profile();
 | 
			
		||||
            $mention_profile->profile_id = $profile->id;
 | 
			
		||||
            $mention_profile->profileurl = $profile->profileurl;
 | 
			
		||||
            $mention_profile->insert();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $profile;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getProfile() {
 | 
			
		||||
        return Profile::getKV('id', $this->profile_id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								plugins/MentionURL/lib/util.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								plugins/MentionURL/lib/util.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
function mention_url_representative_hcard($url, $fn=null, $mf2=null) {
 | 
			
		||||
   if(!$mf2) {
 | 
			
		||||
       $request = HTTPClient::start();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $response = $request->get($url);
 | 
			
		||||
        } catch(Exception $ex) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $url = $response->getEffectiveUrl();
 | 
			
		||||
        $mf2 = new Mf2\Parser($response->getBody(), $url);
 | 
			
		||||
        $mf2 = $mf2->parse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $hcard = null;
 | 
			
		||||
 | 
			
		||||
    if(!empty($mf2['items'])) {
 | 
			
		||||
        $hcards = array();
 | 
			
		||||
        foreach($mf2['items'] as $item) {
 | 
			
		||||
            if(!in_array('h-card', $item['type'])) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // We found a match, return it immediately
 | 
			
		||||
            if(isset($item['properties']['url']) && in_array($url, $item['properties']['url'])) {
 | 
			
		||||
                $hcard = $item['properties'];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Let's keep all the hcards for later, to return one of them at least
 | 
			
		||||
            $hcards[] = $item['properties'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // No match immediately for the url we expected, but there were h-cards found
 | 
			
		||||
        if (count($hcards) > 0) {
 | 
			
		||||
            $hcard = $hcards[0];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!$hcard && $fn) {
 | 
			
		||||
        $hcard = array('name' => array($fn));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!$hcard && $response) {
 | 
			
		||||
        preg_match('/<title>([^<]+)/', $response->getBody(), $match);
 | 
			
		||||
        $hcard = array('name' => array($match[1]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if($hcard && !$hcard['url']) {
 | 
			
		||||
        $hcard['url'] = array($url);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $hcard;
 | 
			
		||||
}
 | 
			
		||||
@@ -297,10 +297,13 @@ class OStatusPlugin extends Plugin
 | 
			
		||||
                    $oprofile = Ostatus_profile::ensureWebfinger($target);
 | 
			
		||||
                    if ($oprofile instanceof Ostatus_profile && !$oprofile->isGroup()) {
 | 
			
		||||
                        $profile = $oprofile->localProfile();
 | 
			
		||||
                        $text = !empty($profile->nickname) && mb_strlen($profile->nickname) < mb_strlen($target) ?
 | 
			
		||||
                                $profile->nickname : $target;
 | 
			
		||||
                        $matches[$pos] = array('mentioned' => array($profile),
 | 
			
		||||
                                               'type' => 'mention',
 | 
			
		||||
                                               'text' => $target,
 | 
			
		||||
                                               'text' => $text,
 | 
			
		||||
                                               'position' => $pos,
 | 
			
		||||
                                               'length' => mb_strlen($target),
 | 
			
		||||
                                               'url' => $profile->getUrl());
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (Exception $e) {
 | 
			
		||||
@@ -310,7 +313,7 @@ class OStatusPlugin extends Plugin
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Profile matches: @example.com/mublog/user
 | 
			
		||||
        if (preg_match_all('!(?:^|\s+)@((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)!',
 | 
			
		||||
        if (preg_match_all('!(?:^|\s+)@((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)*)!',
 | 
			
		||||
                       $text,
 | 
			
		||||
                       $wmatches,
 | 
			
		||||
                       PREG_OFFSET_CAPTURE)) {
 | 
			
		||||
@@ -324,10 +327,13 @@ class OStatusPlugin extends Plugin
 | 
			
		||||
                        $oprofile = Ostatus_profile::ensureProfileURL($url);
 | 
			
		||||
                        if ($oprofile instanceof Ostatus_profile && !$oprofile->isGroup()) {
 | 
			
		||||
                            $profile = $oprofile->localProfile();
 | 
			
		||||
                            $text = !empty($profile->nickname) && mb_strlen($profile->nickname) < mb_strlen($target) ?
 | 
			
		||||
                                    $profile->nickname : $target;
 | 
			
		||||
                            $matches[$pos] = array('mentioned' => array($profile),
 | 
			
		||||
                                                   'type' => 'mention',
 | 
			
		||||
                                                   'text' => $target,
 | 
			
		||||
                                                   'text' => $text,
 | 
			
		||||
                                                   'position' => $pos,
 | 
			
		||||
                                                   'length' => mb_strlen($target),
 | 
			
		||||
                                                   'url' => $profile->getUrl());
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user