activitycontext.php 6.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * An activity
 *
 * PHP version 5
 *
 * LICENCE: 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/>.
 *
 * @category  Feed
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

class ActivityContext
{
    public $replyToID;
    public $replyToUrl;
    public $location;
40
    public $attention = array();    // 'uri' => 'type'
41
    public $conversation;
42
    public $scope;
43 44 45 46 47

    const THR     = 'http://purl.org/syndication/thread/1.0';
    const GEORSS  = 'http://www.georss.org/georss';
    const OSTATUS = 'http://ostatus.org/schema/1.0';

48 49 50
    const INREPLYTO  = 'in-reply-to';
    const REF        = 'ref';
    const HREF       = 'href';
51 52

    // OStatus element names with prefixes
53
    const OBJECTTYPE = 'ostatus:object-type';   // FIXME: Undocumented!
54
    const CONVERSATION = 'ostatus:conversation';
55 56 57

    const POINT     = 'point';

58
    const MENTIONED    = 'mentioned';
59

60 61
    const ATTN_PUBLIC  = 'http://activityschema.org/collection/public';

62
    function __construct($element = null)
63
    {
64 65 66 67
        if (empty($element)) {
            return;
        }

68 69 70 71 72 73 74 75 76
        $replyToEl = ActivityUtils::child($element, self::INREPLYTO, self::THR);

        if (!empty($replyToEl)) {
            $this->replyToID  = $replyToEl->getAttribute(self::REF);
            $this->replyToUrl = $replyToEl->getAttribute(self::HREF);
        }

        $this->location = $this->getLocation($element);

77 78 79 80 81 82 83 84
        $convs = $element->getElementsByTagNameNS(self::OSTATUS, self::CONVERSATION);
        foreach ($convs as $conv) {
            $this->conversation = $conv->textContent;
        }
        if (empty($this->conversation)) {
            // fallback to the atom:link rel="ostatus:conversation" element
            $this->conversation = ActivityUtils::getLink($element, self::CONVERSATION);
        }
85 86 87 88 89 90 91 92

        // Multiple attention links allowed

        $links = $element->getElementsByTagNameNS(ActivityUtils::ATOM, ActivityUtils::LINK);

        for ($i = 0; $i < $links->length; $i++) {
            $link = $links->item($i);

93 94 95 96
            $linkRel  = $link->getAttribute(ActivityUtils::REL);
            $linkHref = $link->getAttribute(self::HREF);
            if ($linkRel == self::MENTIONED && $linkHref !== '') {
                $this->attention[$linkHref] = $link->getAttribute(ActivityContext::OBJECTTYPE);
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
            }
        }
    }

    /**
     * Parse location given as a GeoRSS-simple point, if provided.
     * http://www.georss.org/simple
     *
     * @param feed item $entry
     * @return mixed Location or false
     */
    function getLocation($dom)
    {
        $points = $dom->getElementsByTagNameNS(self::GEORSS, self::POINT);

        for ($i = 0; $i < $points->length; $i++) {
            $point = $points->item($i)->textContent;
            return self::locationFromPoint($point);
        }

        return null;
    }

    // XXX: Move to ActivityUtils or Location?
    static function locationFromPoint($point)
    {
        $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace"
        $point = preg_replace('/\s+/', ' ', $point);
        $point = trim($point);
        $coords = explode(' ', $point);
        if (count($coords) == 2) {
            list($lat, $lon) = $coords;
            if (is_numeric($lat) && is_numeric($lon)) {
                common_log(LOG_INFO, "Looking up location for $lat $lon from georss point");
                return Location::fromLatLon($lat, $lon);
            }
        }
        common_log(LOG_ERR, "Ignoring bogus georss:point value $point");
        return null;
    }
137 138 139 140 141 142 143

    /**
     * Returns context (StatusNet stuff) as an array suitable for serializing
     * in JSON. Right now context stuff is an extension to Activity.
     *
     * @return array the context
     */
144

145 146 147 148
    function asArray()
    {
        $context = array();

149
        $context['inReplyTo']    = $this->getInReplyToArray();
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        $context['conversation'] = $this->conversation;

        return array_filter($context);
    }

    /**
     * Returns an array of arrays representing Activity Objects (intended to be
     * serialized in JSON) that represent WHO the Activity is supposed to
     * be received by. This is not really specified but appears in an example
     * of the current spec as an extension. We might want to figure out a JSON
     * serialization for OStatus and use that to express mentions instead.
     *
     * XXX: People's ideas on how to do this are all over the place
     *
     * @return array the array of recipients
     */
166

167 168 169 170
    function getToArray()
    {
        $tos = array();

171
        foreach ($this->attention as $attnUrl => $attnType) {
172
            $to = array(
173 174
                'objectType' => $attnType,  // can be empty
                'id'         => $attnUrl,
175
            );
176 177 178 179 180 181
            $tos[] = $to;
        }

        return $tos;
    }

182 183 184 185 186
    /**
     * Return an array for the notices this notice is a reply to 
     * suitable for serializing as JSON note objects.
     *
     * @return array the array of notes
187 188 189 190
     */

     function getInReplyToArray()
     {
191 192 193
         if (empty($this->replyToID) && empty($this->replyToUrl)) {
             return null;
         }
194

195
         $replyToObj = array('objectType' => 'note');
196

197 198 199 200 201
         // XXX: Possibly shorten this to just the numeric ID?
         //      Currently, it's the full URI of the notice.
         if (!empty($this->replyToID)) {
             $replyToObj['id'] = $this->replyToID;
         }
202 203 204 205
         if (!empty($this->replyToUrl)) {
             $replyToObj['url'] = $this->replyToUrl;
         }

206
         return $replyToObj;
207 208
     }

209
}
210