]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge commit 'refs/merge-requests/153' of git://gitorious.org/statusnet/mainline...
authorZach Copley <zach@status.net>
Tue, 1 Mar 2011 00:36:59 +0000 (16:36 -0800)
committerZach Copley <zach@status.net>
Tue, 1 Mar 2011 00:36:59 +0000 (16:36 -0800)
12 files changed:
classes/Notice.php
classes/statusnet.ini
lib/util.php
plugins/ExtendedProfile/ExtendedProfilePlugin.php [new file with mode: 0644]
plugins/ExtendedProfile/Profile_detail.php [new file with mode: 0644]
plugins/ExtendedProfile/extendedprofile.php [new file with mode: 0644]
plugins/ExtendedProfile/extendedprofilewidget.php [new file with mode: 0644]
plugins/ExtendedProfile/profiledetail.css [new file with mode: 0644]
plugins/ExtendedProfile/profiledetailaction.php [new file with mode: 0644]
plugins/ExtendedProfile/profiledetailsettingsaction.php [new file with mode: 0644]
plugins/TwitterBridge/twitterimport.php
tests/URLDetectionTest.php

index a25991fa322fc779d17299fa5944ba2a7a9caaa8..141ae8fd44883c3cb012214fd1a35b239d33801e 100644 (file)
@@ -1072,6 +1072,7 @@ class Notice extends Memcached_DataObject
 
             $reply->notice_id  = $this->id;
             $reply->profile_id = $profile->id;
+            $reply->modified   = $this->created;
 
             common_log(LOG_INFO, __METHOD__ . ": saving reply: notice $this->id to profile $profile->id");
 
@@ -1132,6 +1133,7 @@ class Notice extends Memcached_DataObject
 
                 $reply->notice_id  = $this->id;
                 $reply->profile_id = $mentioned->id;
+                $reply->modified   = $this->created;
 
                 $id = $reply->insert();
 
index ef631e28d376668940e579f05cc0a300ad14cab4..1916c2513972aa78339b3d5270c31524eee10f7d 100644 (file)
@@ -502,7 +502,8 @@ uri = U
 [reply]
 notice_id = 129
 profile_id = 129
-modified = 384
+modified = 142
+;modified = 384 ; skipping the mysql_timestamp mode so we can override its setting
 replied_id = 1
 
 [reply__keys]
index f734062eced327cec4423eaf9732634778af207d..e5b0c86e06160599436901a3f84c4a8717d2932e 100644 (file)
@@ -925,11 +925,11 @@ function common_linkify($url) {
     // functions
     $url = htmlspecialchars_decode($url);
 
-   if(strpos($url, '@') !== false && strpos($url, ':') === false) {
-       //url is an email address without the mailto: protocol
-       $canon = "mailto:$url";
-       $longurl = "mailto:$url";
-   }else{
+    if (strpos($url, '@') !== false && strpos($url, ':') === false && Validate::email($url)) {
+        //url is an email address without the mailto: protocol
+        $canon = "mailto:$url";
+        $longurl = "mailto:$url";
+    } else {
 
         $canon = File_redirection::_canonUrl($url);
 
diff --git a/plugins/ExtendedProfile/ExtendedProfilePlugin.php b/plugins/ExtendedProfile/ExtendedProfilePlugin.php
new file mode 100644 (file)
index 0000000..3f541c0
--- /dev/null
@@ -0,0 +1,121 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Extra profile bio-like fields
+ *
+ * @package ExtendedProfilePlugin
+ * @maintainer Brion Vibber <brion@status.net>
+ */
+class ExtendedProfilePlugin extends Plugin
+{
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'ExtendedProfile',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Brion Vibber',
+                            'homepage' => 'http://status.net/wiki/Plugin:ExtendedProfile',
+                            'rawdescription' =>
+                            _m('UI extensions for additional profile fields.'));
+
+        return true;
+    }
+
+    /**
+     * Autoloader
+     *
+     * Loads our classes if they're requested.
+     *
+     * @param string $cls Class requested
+     *
+     * @return boolean hook return
+     */
+    function onAutoload($cls)
+    {
+        $lower = strtolower($cls);
+        switch ($lower)
+        {
+        case 'extendedprofile':
+        case 'extendedprofilewidget':
+        case 'profiledetailaction':
+        case 'profiledetailsettingsaction':
+            require_once dirname(__FILE__) . '/' . $lower . '.php';
+            return false;
+        case 'profile_detail':
+            require_once dirname(__FILE__) . '/' . ucfirst($lower) . '.php';
+            return false;
+        default:
+            return true;
+        }
+    }
+
+    /**
+     * Add paths to the router table
+     *
+     * Hook for RouterInitialized event.
+     *
+     * @param Net_URL_Mapper $m URL mapper
+     *
+     * @return boolean hook return
+     */
+    function onStartInitializeRouter($m)
+    {
+        $m->connect(':nickname/detail',
+                array('action' => 'profiledetail'),
+                array('nickname' => Nickname::DISPLAY_FMT));
+        $m->connect('settings/profile/detail',
+                array('action' => 'profiledetailsettings'));
+
+        return true;
+    }
+
+    function onCheckSchema()
+    {
+        $schema = Schema::get();
+        $schema->ensureTable('profile_detail', Profile_detail::schemaDef());
+
+        // @hack until key definition support is merged
+        Profile_detail::fixIndexes($schema);
+        return true;
+    }
+
+    function onEndAccountSettingsProfileMenuItem($widget, $menu)
+    {
+        // TRANS: Link title attribute in user account settings menu.
+        $title = _('Change additional profile settings');
+        // TRANS: Link description in user account settings menu.
+        $widget->showMenuItem('profiledetailsettings',_m('Details'),$title);
+        return true;
+    }
+
+    function onEndProfilePageProfileElements(HTMLOutputter $out, Profile $profile) {
+        $user = User::staticGet('id', $profile->id);
+        if ($user) {
+            $url = common_local_url('profiledetail', array('nickname' => $user->nickname));
+            $out->element('a', array('href' => $url), _m('More details...'));
+        }
+        return;
+    }
+
+}
diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php
new file mode 100644 (file)
index 0000000..6fd96cc
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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('STATUSNET')) {
+    exit(1);
+}
+
+class Profile_detail extends Memcached_DataObject
+{
+    public $__table = 'submirror';
+
+    public $id;
+
+    public $profile_id;
+    public $field;
+    public $field_index; // relative ordering of multiple values in the same field
+
+    public $value; // primary text value
+    public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM
+    public $ref_profile; // for people types, allows pointing to a known profile in the system
+
+    public $created;
+    public $modified;
+
+    public /*static*/ function staticGet($k, $v=null)
+    {
+        return parent::staticGet(__CLASS__, $k, $v);
+    }
+
+    /**
+     * return table definition for DB_DataObject
+     *
+     * DB_DataObject needs to know something about the table to manipulate
+     * instances. This method provides all the DB_DataObject needs to know.
+     *
+     * @return array array of column definitions
+     */
+
+    function table()
+    {
+        return array('id' =>  DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+
+                     'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+                     'field' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+                     'field_index' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+
+                     'value' => DB_DATAOBJECT_STR,
+                     'rel' => DB_DATAOBJECT_STR,
+                     'ref_profile' => DB_DATAOBJECT_ID,
+
+                     'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
+                     'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
+    }
+
+    static function schemaDef()
+    {
+        // @fixme need a reverse key on (subscribed, subscriber) as well
+        return array(new ColumnDef('id', 'integer',
+                                   null, false, 'PRI'),
+
+                     // @fixme need a unique index on these three
+                     new ColumnDef('profile_id', 'integer',
+                                   null, false),
+                     new ColumnDef('field', 'varchar',
+                                   16, false),
+                     new ColumnDef('field_index', 'integer',
+                                   null, false),
+
+                     new ColumnDef('value', 'text',
+                                   null, true),
+                     new ColumnDef('rel', 'varchar',
+                                   16, true),
+                     new ColumnDef('ref_profile', 'integer',
+                                   null, true),
+
+                     new ColumnDef('created', 'datetime',
+                                   null, false),
+                     new ColumnDef('modified', 'datetime',
+                                   null, false));
+    }
+
+    /**
+     * Temporary hack to set up the compound index, since we can't do
+     * it yet through regular Schema interface. (Coming for 1.0...)
+     *
+     * @param Schema $schema
+     * @return void
+     */
+    static function fixIndexes($schema)
+    {
+        try {
+            // @fixme this won't be a unique index... SIGH
+            $schema->createIndex('profile_detail', array('profile_id', 'field', 'field_index'));
+        } catch (Exception $e) {
+            common_log(LOG_ERR, __METHOD__ . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * return key definitions for DB_DataObject
+     *
+     * DB_DataObject needs to know about keys that the table has; this function
+     * defines them.
+     *
+     * @return array key definitions
+     */
+
+    function keys()
+    {
+        return array_keys($this->keyTypes());
+    }
+
+    /**
+     * return key definitions for Memcached_DataObject
+     *
+     * Our caching system uses the same key definitions, but uses a different
+     * method to get them.
+     *
+     * @return array key definitions
+     */
+
+    function keyTypes()
+    {
+        // @fixme keys
+        // need a sane key for reverse lookup too
+        return array('id' => 'K');
+    }
+
+    function sequenceKey()
+    {
+        return array('id', true);
+    }
+
+}
diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php
new file mode 100644 (file)
index 0000000..7f69f90
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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('STATUSNET')) {
+    exit(1);
+}
+
+class ExtendedProfile
+{
+    function __construct(Profile $profile)
+    {
+        $this->profile = $profile;
+        $this->sections = $this->getSections();
+        $this->fields = $this->loadFields();
+    }
+
+    function loadFields()
+    {
+        $detail = new Profile_detail();
+        $detail->profile_id = $this->profile->id;
+        $detail->find();
+        
+        while ($detail->get()) {
+            $fields[$detail->field][] = clone($detail);
+        }
+        return $fields;
+    }
+
+    function getSections()
+    {
+        return array(
+            'basic' => array(
+                'label' => _m('Personal'),
+                'fields' => array(
+                    'fullname' => array(
+                        'label' => _m('Full name'),
+                        'profile' => 'fullname',
+                        'vcard' => 'fn',
+                    ),
+                    'title' => array(
+                        'label' => _m('Title'),
+                        'vcard' => 'title',
+                    ),
+                    'manager' => array(
+                        'label' => _m('Manager'),
+                        'type' => 'person',
+                        'vcard' => 'x-manager',
+                    ),
+                    'location' => array(
+                        'label' => _m('Location'),
+                        'profile' => 'location'
+                    ),
+                    'bio' => array(
+                        'label' => _m('Bio'),
+                        'type' => 'textarea',
+                        'profile' => 'bio',
+                    ),
+                    'tags' => array(
+                        'label' => _m('Tags'),
+                        'type' => 'tags',
+                        'profile' => 'tags',
+                    ),
+                ),
+            ),
+            'contact' => array(
+                'label' => _m('Contact'),
+                'fields' => array(
+                    'phone' => array(
+                        'label' => _m('Phone'),
+                        'type' => 'phone',
+                        'multi' => true,
+                        'vcard' => 'tel',
+                    ),
+                    'im' => array(
+                        'label' => _m('IM'),
+                        'type' => 'im',
+                        'multi' => true,
+                    ),
+                    'website' => array(
+                        'label' => _m('Websites'),
+                        'type' => 'website',
+                        'multi' => true,
+                    ),
+                ),
+            ),
+            'personal' => array(
+                'label' => _m('Personal'),
+                'fields' => array(
+                    'birthday' => array(
+                        'label' => _m('Birthday'),
+                        'type' => 'date',
+                        'vcard' => 'bday',
+                    ),
+                    'spouse' => array(
+                        'label' => _m('Spouse\'s name'),
+                        'vcard' => 'x-spouse',
+                    ),
+                    'kids' => array(
+                        'label' => _m('Kids\' names')
+                    ),
+                ),
+            ),
+            'experience' => array(
+                'label' => _m('Work experience'),
+                'fields' => array(
+                    'experience' => array(
+                        'type' => 'experience',
+                        'label' => _m('Employer'),
+                    ),
+                ),
+            ),
+            'education' => array(
+                'label' => _m('Education'),
+                'fields' => array(
+                    'education' => array(
+                        'type' => 'education',
+                        'label' => _m('Institution'),
+                    ),
+                ),
+            ),
+        );
+    }
+}
diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php
new file mode 100644 (file)
index 0000000..bf9b405
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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('STATUSNET')) {
+    exit(1);
+}
+
+class ExtendedProfileWidget extends Widget
+{
+    const EDITABLE=true;
+
+    protected $profile;
+    protected $ext;
+
+    public function __construct(XMLOutputter $out=null, Profile $profile=null, $editable=false)
+    {
+        parent::__construct($out);
+
+        $this->profile = $profile;
+        $this->ext = new ExtendedProfile($this->profile);
+
+        $this->editable = $editable;
+    }
+
+    public function show()
+    {
+        $sections = $this->ext->getSections();
+        foreach ($sections as $name => $section) {
+            $this->showExtendedProfileSection($name, $section);
+        }
+    }
+
+    protected function showExtendedProfileSection($name, $section)
+    {
+        $this->out->element('h3', null, $section['label']);
+        $this->out->elementStart('table', array('class' => 'extended-profile'));
+        foreach ($section['fields'] as $fieldName => $field) {
+            $this->showExtendedProfileField($fieldName, $field);
+        }
+        $this->out->elementEnd('table');
+    }
+
+    protected function showExtendedProfileField($name, $field)
+    {
+        $this->out->elementStart('tr');
+
+        $this->out->element('th', null, $field['label']);
+
+        $this->out->elementStart('td');
+        if ($this->editable) {
+            $this->showEditableField($name, $field);
+        } else {
+            $this->showFieldValue($name, $field);
+        }
+        $this->out->elementEnd('td');
+
+        $this->out->elementEnd('tr');
+    }
+
+    protected function showFieldValue($name, $field)
+    {
+        $this->out->text($name);
+    }
+
+    protected function showEditableField($name, $field)
+    {
+        $out = $this->out;
+        //$out = new HTMLOutputter();
+        // @fixme
+        $type = strval(@$field['type']);
+        $id = "extprofile-" . $name;
+        $value = 'placeholder';
+
+        switch ($type) {
+            case '':
+            case 'text':
+                $out->input($id, null, $value);
+                break;
+            case 'textarea':
+                $out->textarea($id, null, $value);
+                break;
+            default:
+                $out->input($id, null, "TYPE: $type");
+        }
+    }
+}
diff --git a/plugins/ExtendedProfile/profiledetail.css b/plugins/ExtendedProfile/profiledetail.css
new file mode 100644 (file)
index 0000000..836b647
--- /dev/null
@@ -0,0 +1,22 @@
+/* Note the #content is only needed to override weird crap in default styles */
+
+#content table.extended-profile {
+    width: 100%;
+    border-collapse: separate;
+    border-spacing: 8px;
+}
+#content table.extended-profile th {
+    color: #777;
+    background-color: #eee;
+    width: 150px;
+
+    padding-top: 0; /* override bizarre theme defaults */
+
+    text-align: right;
+    padding-right: 8px;
+}
+#content table.extended-profile td {
+    padding: 0; /* override bizarre theme defaults */
+
+    padding-left: 8px;
+}
\ No newline at end of file
diff --git a/plugins/ExtendedProfile/profiledetailaction.php b/plugins/ExtendedProfile/profiledetailaction.php
new file mode 100644 (file)
index 0000000..a4bb129
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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('STATUSNET')) {
+    exit(1);
+}
+
+class ProfileDetailAction extends ProfileAction
+{
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function title()
+    {
+        return $this->profile->getFancyName();
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PersonalGroupNav($this);
+        $nav->show();
+    }
+
+    function showStylesheets() {
+        parent::showStylesheets();
+        $this->cssLink('plugins/ExtendedProfile/profiledetail.css');
+        return true;
+    }
+
+    function handle($args)
+    {
+        $this->showPage();
+    }
+
+    function showContent()
+    {
+        $cur = common_current_user();
+        if ($cur && $cur->id == $this->profile->id) { // your own page
+            $this->elementStart('div', 'entity_actions');
+            $this->elementStart('li', 'entity_edit');
+            $this->element('a', array('href' => common_local_url('profiledetailsettings'),
+                                      // TRANS: Link title for link on user profile.
+                                      'title' => _m('Edit extended profile settings')),
+                           // TRANS: Link text for link on user profile.
+                           _m('Edit'));
+            $this->elementEnd('li');
+            $this->elementEnd('div');
+        }
+
+        $widget = new ExtendedProfileWidget($this, $this->profile);
+        $widget->show();
+    }
+}
diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php
new file mode 100644 (file)
index 0000000..77d755c
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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('STATUSNET')) {
+    exit(1);
+}
+
+class ProfileDetailSettingsAction extends AccountSettingsAction
+{
+
+    function title()
+    {
+        return _m('Extended profile settings');
+    }
+
+    /**
+     * Instructions for use
+     *
+     * @return instructions for use
+     */
+    function getInstructions()
+    {
+        // TRANS: Usage instructions for profile settings.
+        return _('You can update your personal profile info here '.
+                 'so people know more about you.');
+    }
+
+    function showStylesheets() {
+        parent::showStylesheets();
+        $this->cssLink('plugins/ExtendedProfile/profiledetail.css');
+        return true;
+    }
+
+    function handle($args)
+    {
+        $this->showPage();
+    }
+
+    function showContent()
+    {
+        $cur = common_current_user();
+        $profile = $cur->getProfile();
+
+        $widget = new ExtendedProfileWidget($this, $profile, ExtendedProfileWidget::EDITABLE);
+        $widget->show();
+    }
+}
index 5ddf5380d745128a2057a6085bb1a01435b1bb74..0eacfcd62c57cf10dc05350dc0a52ff88347d726 100644 (file)
@@ -675,6 +675,7 @@ class TwitterImport
                     $reply = new Reply();
                     $reply->notice_id  = $notice->id;
                     $reply->profile_id = $user->id;
+                    $reply->modified   = $notice->created;
                     common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$notice->id} to profile {$user->id}");
                     $id = $reply->insert();
                 }
index eac7ba3f5c766032ad14d5d5103793299e5458b0..dc017ac616f63bdd2fcae5c607c6f4db0978c090 100644 (file)
@@ -20,6 +20,8 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
     public function testProduction($content, $expected)
     {
         $rendered = common_render_text($content);
+        // hack!
+        $rendered = preg_replace('/id="attachment-\d+"/', 'id="attachment-XXX"', $rendered);
         $this->assertEquals($expected, $rendered);
     }
 
@@ -269,7 +271,13 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
                      array('file.html',
                            'file.html'),
                      array('file.php',
-                           'file.php')
+                           'file.php'),
+
+                     // scheme-less HTTP URLs with @ in the path: http://status.net/open-source/issues/2248
+                     array('http://flickr.com/photos/34807140@N05/3838905434',
+                           '<a href="http://flickr.com/photos/34807140@N05/3838905434" title="http://flickr.com/photos/34807140@N05/3838905434" class="attachment thumbnail" id="attachment-XXX" rel="nofollow external">http://flickr.com/photos/34807140@N05/3838905434</a>'),
+                     array('flickr.com/photos/34807140@N05/3838905434',
+                           '<a href="http://flickr.com/photos/34807140@N05/3838905434" title="http://flickr.com/photos/34807140@N05/3838905434" class="attachment thumbnail" id="attachment-XXX" rel="nofollow external">flickr.com/photos/34807140@N05/3838905434</a>'),
                      );
     }
 }