User.php 23.4 KB
Newer Older
Evan Prodromou's avatar
Evan Prodromou committed
1
<?php
Evan Prodromou's avatar
Evan Prodromou committed
2
/*
3
 * StatusNet - the distributed open-source microblogging tool
4
 * Copyright (C) 2008, 2009, StatusNet, Inc.
Evan Prodromou's avatar
Evan Prodromou committed
5
 *
Evan Prodromou's avatar
Evan Prodromou committed
6 7 8 9
 * 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.
Evan Prodromou's avatar
Evan Prodromou committed
10
 *
Evan Prodromou's avatar
Evan Prodromou committed
11 12 13 14
 * 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.
Evan Prodromou's avatar
Evan Prodromou committed
15
 *
Evan Prodromou's avatar
Evan Prodromou committed
16 17 18 19
 * 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/>.
 */

20
if (!defined('STATUSNET') && !defined('LACONICA')) {
Evan Prodromou's avatar
Evan Prodromou committed
21 22
    exit(1);
}
23

Evan Prodromou's avatar
Evan Prodromou committed
24 25 26
/**
 * Table Definition for user
 */
Evan Prodromou's avatar
Evan Prodromou committed
27

28
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
29
require_once 'Validate.php';
Evan Prodromou's avatar
Evan Prodromou committed
30

31
class User extends Memcached_DataObject
Evan Prodromou's avatar
Evan Prodromou committed
32 33 34 35 36 37
{
    ###START_AUTOCODE
    /* the code below is auto generated do not remove the above tag */

    public $__table = 'user';                            // table name
    public $id;                              // int(4)  primary_key not_null
Evan Prodromou's avatar
Evan Prodromou committed
38
    public $nickname;                        // varchar(64)  unique_key
39
    public $password;                        // varchar(255)
Evan Prodromou's avatar
Evan Prodromou committed
40
    public $email;                           // varchar(255)  unique_key
Evan Prodromou's avatar
Evan Prodromou committed
41
    public $incomingemail;                   // varchar(255)  unique_key
42
    public $emailnotifysub;                  // tinyint(1)   default_1
43
    public $emailnotifyfav;                  // tinyint(1)   default_1
Evan Prodromou's avatar
Evan Prodromou committed
44
    public $emailnotifynudge;                // tinyint(1)   default_1
Evan Prodromou's avatar
Evan Prodromou committed
45
    public $emailnotifymsg;                  // tinyint(1)   default_1
46
    public $emailnotifyattn;                 // tinyint(1)   default_1
mikec's avatar
mikec committed
47
    public $emailmicroid;                    // tinyint(1)   default_1
48 49
    public $language;                        // varchar(50)
    public $timezone;                        // varchar(50)
mikec's avatar
mikec committed
50
    public $emailpost;                       // tinyint(1)   default_1
51
    public $jabber;                          // varchar(255)  unique_key
52 53
    public $jabbernotify;                    // tinyint(1)
    public $jabberreplies;                   // tinyint(1)
54
    public $jabbermicroid;                   // tinyint(1)   default_1
55
    public $updatefrompresence;              // tinyint(1)
56
    public $sms;                             // varchar(64)  unique_key
57 58 59 60
    public $carrier;                         // int(4)
    public $smsnotify;                       // tinyint(1)
    public $smsreplies;                      // tinyint(1)
    public $smsemail;                        // varchar(255)
61
    public $uri;                             // varchar(255)  unique_key
62
    public $autosubscribe;                   // tinyint(1)
Evan Prodromou's avatar
Evan Prodromou committed
63
    public $urlshorteningservice;            // varchar(50)   default_ur1.ca
64
    public $inboxed;                         // tinyint(1)
65 66
    public $design_id;                       // int(4)
    public $viewdesigns;                     // tinyint(1)   default_1
Evan Prodromou's avatar
Evan Prodromou committed
67 68 69 70
    public $created;                         // datetime()   not_null
    public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP

    /* Static get */
71
    function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User',$k,$v); }
Evan Prodromou's avatar
Evan Prodromou committed
72 73 74

    /* the code above is auto generated do not remove the tag below */
    ###END_AUTOCODE
Evan Prodromou's avatar
Evan Prodromou committed
75

76 77
    function getProfile()
    {
78 79 80
        return Profile::staticGet('id', $this->id);
    }

81 82
    function isSubscribed($other)
    {
83
        assert(!is_null($other));
Evan Prodromou's avatar
Evan Prodromou committed
84
        // XXX: cache results of this query
85 86 87 88 89
        $sub = Subscription::pkeyGet(array('subscriber' => $this->id,
                                           'subscribed' => $other->id));
        return (is_null($sub)) ? false : true;
    }

90
    // 'update' won't write key columns, so we have to do it ourselves.
91

92 93
    function updateKeys(&$orig)
    {
94 95 96 97 98 99 100
        $parts = array();
        foreach (array('nickname', 'email', 'jabber', 'incomingemail', 'sms', 'carrier', 'smsemail', 'language', 'timezone') as $k) {
            if (strcmp($this->$k, $orig->$k) != 0) {
                $parts[] = $k . ' = ' . $this->_quote($this->$k);
            }
        }
        if (count($parts) == 0) {
Evan Prodromou's avatar
Evan Prodromou committed
101
            // No changes
102 103 104 105
            return true;
        }
        $toupdate = implode(', ', $parts);

106
        $table = common_database_tablename($this->tableName());
107 108 109 110 111 112 113 114 115 116
        $qry = 'UPDATE ' . $table . ' SET ' . $toupdate .
          ' WHERE id = ' . $this->id;
        $orig->decache();
        $result = $this->query($qry);
        if ($result) {
            $this->encache();
        }
        return $result;
    }

117
    static function allowed_nickname($nickname)
118
    {
Evan Prodromou's avatar
Evan Prodromou committed
119
        // XXX: should already be validated for size, content, etc.
120
        $blacklist = common_config('nickname', 'blacklist');
121 122 123 124 125 126 127

        //all directory and file names should be blacklisted
        $d = dir(INSTALLDIR);
        while (false !== ($entry = $d->read())) {
            $blacklist[]=$entry;
        }
        $d->close();
128 129 130 131 132 133 134 135 136

        //all top level names in the router should be blacklisted
        $router = Router::get();
        foreach(array_keys($router->m->getPaths()) as $path){
            if(preg_match('/^\/(.*?)[\/\?]/',$path,$matches)){
                $blacklist[]=$matches[1];
            }
        }
        return !in_array($nickname, $blacklist);
137 138
    }

139 140
    function getCurrentNotice($dt=null)
    {
141 142
        $profile = $this->getProfile();
        if (!$profile) {
Evan Prodromou's avatar
Evan Prodromou committed
143
            return null;
144 145 146 147
        }
        return $profile->getCurrentNotice($dt);
    }

148 149
    function getCarrier()
    {
150 151 152
        return Sms_carrier::staticGet('id', $this->carrier);
    }

153 154
    function subscribeTo($other)
    {
155 156 157 158
        $sub = new Subscription();
        $sub->subscriber = $this->id;
        $sub->subscribed = $other->id;

Evan Prodromou's avatar
Evan Prodromou committed
159
        $sub->created = common_sql_now(); // current time
160 161 162 163 164 165 166

        if (!$sub->insert()) {
            return false;
        }

        return true;
    }
167

168 169
    function hasBlocked($other)
    {
170

171
        $block = Profile_block::get($this->id, $other->id);
172 173 174 175 176 177 178 179 180 181 182

        if (is_null($block)) {
            $result = false;
        } else {
            $result = true;
            $block->free();
        }

        return $result;
    }

183
    static function register($fields) {
184

Evan Prodromou's avatar
Evan Prodromou committed
185
        // MAGICALLY put fields into current scope
Evan Prodromou's avatar
Evan Prodromou committed
186

187
        extract($fields);
Evan Prodromou's avatar
Evan Prodromou committed
188

189
        $profile = new Profile();
190

191
        $profile->query('BEGIN');
192

193 194 195 196 197 198
        if(!empty($email))
        {
            $email = common_canonical_email($email);
        }

        $nickname = common_canonical_nickname($nickname);
199
        $profile->nickname = $nickname;
200 201 202 203
        if(! User::allowed_nickname($nickname)){
            common_log(LOG_WARNING, sprintf("Attempted to register a nickname that is not allowed: %s", $profile->nickname),
                           __FILE__);
        }
204
        $profile->profileurl = common_profile_url($nickname);
Evan Prodromou's avatar
Evan Prodromou committed
205

206
        if (!empty($fullname)) {
207 208
            $profile->fullname = $fullname;
        }
209
        if (!empty($homepage)) {
210 211
            $profile->homepage = $homepage;
        }
212
        if (!empty($bio)) {
213 214
            $profile->bio = $bio;
        }
215
        if (!empty($location)) {
216
            $profile->location = $location;
217 218 219 220 221 222 223 224 225

            $loc = Location::fromName($location);

            if (!empty($loc)) {
                $profile->lat         = $loc->lat;
                $profile->lon         = $loc->lon;
                $profile->location_id = $loc->location_id;
                $profile->location_ns = $loc->location_ns;
            }
226
        }
Evan Prodromou's avatar
Evan Prodromou committed
227

228
        $profile->created = common_sql_now();
Evan Prodromou's avatar
Evan Prodromou committed
229

230
        $id = $profile->insert();
231

232
        if (empty($id)) {
233
            common_log_db_error($profile, 'INSERT', __FILE__);
Evan Prodromou's avatar
TRUE  
Evan Prodromou committed
234
            return false;
235
        }
Evan Prodromou's avatar
Evan Prodromou committed
236

237
        $user = new User();
Evan Prodromou's avatar
Evan Prodromou committed
238

239 240
        $user->id = $id;
        $user->nickname = $nickname;
Evan Prodromou's avatar
Evan Prodromou committed
241

Evan Prodromou's avatar
Evan Prodromou committed
242
        if (!empty($password)) { // may not have a password for OpenID users
243 244 245
            $user->password = common_munge_password($password, $id);
        }

Evan Prodromou's avatar
Evan Prodromou committed
246
        // Users who respond to invite email have proven their ownership of that address
247

248
        if (!empty($code)) {
249 250 251 252 253 254
            $invite = Invitation::staticGet($code);
            if ($invite && $invite->address && $invite->address_type == 'email' && $invite->address == $email) {
                $user->email = $invite->address;
            }
        }

255 256 257 258
        if(isset($email_confirmed) && $email_confirmed) {
            $user->email = $email;
        }

Evan Prodromou's avatar
Evan Prodromou committed
259
        // This flag is ignored but still set to 1
Evan Prodromou's avatar
Evan Prodromou committed
260

Evan Prodromou's avatar
Evan Prodromou committed
261
        $user->inboxed = 1;
262 263 264 265 266 267 268 269

        $user->created = common_sql_now();
        $user->uri = common_user_uri($user);

        $result = $user->insert();

        if (!$result) {
            common_log_db_error($user, 'INSERT', __FILE__);
Evan Prodromou's avatar
TRUE  
Evan Prodromou committed
270
            return false;
271
        }
272

Evan Prodromou's avatar
Evan Prodromou committed
273
        // Everyone is subscribed to themself
274

275 276 277 278
        $subscription = new Subscription();
        $subscription->subscriber = $user->id;
        $subscription->subscribed = $user->id;
        $subscription->created = $user->created;
Evan Prodromou's avatar
Evan Prodromou committed
279

280 281 282 283
        $result = $subscription->insert();

        if (!$result) {
            common_log_db_error($subscription, 'INSERT', __FILE__);
Evan Prodromou's avatar
TRUE  
Evan Prodromou committed
284
            return false;
285 286
        }

287
        if (!empty($email) && !$user->email) {
288 289 290 291 292 293 294 295 296 297

            $confirm = new Confirm_address();
            $confirm->code = common_confirmation_code(128);
            $confirm->user_id = $user->id;
            $confirm->address = $email;
            $confirm->address_type = 'email';

            $result = $confirm->insert();
            if (!$result) {
                common_log_db_error($confirm, 'INSERT', __FILE__);
Evan Prodromou's avatar
TRUE  
Evan Prodromou committed
298
                return false;
299 300 301
            }
        }

302
        if (!empty($code) && $user->email) {
303 304
            $user->emailChanged();
        }
Evan Prodromou's avatar
Evan Prodromou committed
305

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
        // Default system subscription

        $defnick = common_config('newuser', 'default');

        if (!empty($defnick)) {
            $defuser = User::staticGet('nickname', $defnick);
            if (empty($defuser)) {
                common_log(LOG_WARNING, sprintf("Default user %s does not exist.", $defnick),
                           __FILE__);
            } else {
                $defsub = new Subscription();
                $defsub->subscriber = $user->id;
                $defsub->subscribed = $defuser->id;
                $defsub->created = $user->created;

                $result = $defsub->insert();

                if (!$result) {
                    common_log_db_error($defsub, 'INSERT', __FILE__);
                    return false;
                }
            }
        }

330
        $profile->query('COMMIT');
Evan Prodromou's avatar
Evan Prodromou committed
331

332 333 334
        if ($email && !$user->email) {
            mail_confirm_address($user, $confirm->code, $profile->nickname, $email);
        }
335

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
        // Welcome message

        $welcome = common_config('newuser', 'welcome');

        if (!empty($welcome)) {
            $welcomeuser = User::staticGet('nickname', $welcome);
            if (empty($welcomeuser)) {
                common_log(LOG_WARNING, sprintf("Welcome user %s does not exist.", $defnick),
                           __FILE__);
            } else {
                $notice = Notice::saveNew($welcomeuser->id,
                                          sprintf(_('Welcome to %1$s, @%2$s!'),
                                                  common_config('site', 'name'),
                                                  $user->nickname),
                                          'system');
351
                common_broadcast_notice($notice);
352 353 354
            }
        }

355 356
        return $user;
    }
357

Evan Prodromou's avatar
Evan Prodromou committed
358
    // Things we do when the email changes
Evan Prodromou's avatar
Evan Prodromou committed
359

360 361
    function emailChanged()
    {
Evan Prodromou's avatar
Evan Prodromou committed
362

363 364 365
        $invites = new Invitation();
        $invites->address = $this->email;
        $invites->address_type = 'email';
Evan Prodromou's avatar
Evan Prodromou committed
366

367 368 369 370 371 372 373
        if ($invites->find()) {
            while ($invites->fetch()) {
                $other = User::staticGet($invites->user_id);
                subs_subscribe_to($other, $this);
            }
        }
    }
Evan Prodromou's avatar
Evan Prodromou committed
374

375 376
    function hasFave($notice)
    {
377 378
        $cache = common_memcache();

Evan Prodromou's avatar
Evan Prodromou committed
379
        // XXX: Kind of a hack.
Evan Prodromou's avatar
Evan Prodromou committed
380

381
        if ($cache) {
Evan Prodromou's avatar
Evan Prodromou committed
382 383
            // This is the stream of favorite notices, in rev chron
            // order. This forces it into cache.
Evan Prodromou's avatar
Evan Prodromou committed
384 385 386 387 388 389 390

            $ids = Fave::stream($this->id, 0, NOTICE_CACHE_WINDOW);

            // If it's in the list, then it's a fave

            if (in_array($notice->id, $ids)) {
                return true;
391
            }
Evan Prodromou's avatar
Evan Prodromou committed
392

Evan Prodromou's avatar
Evan Prodromou committed
393 394 395
            // If we're not past the end of the cache window,
            // then the cache has all available faves, so this one
            // is not a fave.
Evan Prodromou's avatar
Evan Prodromou committed
396 397

            if (count($ids) < NOTICE_CACHE_WINDOW) {
398 399
                return false;
            }
Evan Prodromou's avatar
Evan Prodromou committed
400

401
            // Otherwise, cache doesn't have all faves;
Evan Prodromou's avatar
Evan Prodromou committed
402
            // fall through to the default
403
        }
Evan Prodromou's avatar
Evan Prodromou committed
404

405 406 407 408
        $fave = Fave::pkeyGet(array('user_id' => $this->id,
                                    'notice_id' => $notice->id));
        return ((is_null($fave)) ? false : true);
    }
Evan Prodromou's avatar
Evan Prodromou committed
409

410 411
    function mutuallySubscribed($other)
    {
412 413 414
        return $this->isSubscribed($other) &&
          $other->isSubscribed($this);
    }
415

Evan Prodromou's avatar
Evan Prodromou committed
416 417 418 419
    function mutuallySubscribedUsers()
    {
        // 3-way join; probably should get cached
        $UT = common_config('db','type')=='pgsql'?'"user"':'user';
420 421 422
        $qry = "SELECT $UT.* " .
          "FROM subscription sub1 JOIN $UT ON sub1.subscribed = $UT.id " .
          "JOIN subscription sub2 ON $UT.id = sub2.subscriber " .
423
          'WHERE sub1.subscriber = %d and sub2.subscribed = %d ' .
424
          "ORDER BY $UT.nickname";
425 426 427 428 429 430
        $user = new User();
        $user->query(sprintf($qry, $this->id, $this->id));

        return $user;
    }

431 432
    function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
    {
433 434
        $ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
        return Notice::getStreamByIds($ids);
435
    }
436

437 438 439 440 441 442 443 444 445
    function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) {
        $profile = $this->getProfile();
        if (!$profile) {
            return null;
        } else {
            return $profile->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id, $since);
        }
    }

Evan Prodromou's avatar
Evan Prodromou committed
446 447
    function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
    {
448 449
        $profile = $this->getProfile();
        if (!$profile) {
Evan Prodromou's avatar
Evan Prodromou committed
450
            return null;
451
        } else {
452
            return $profile->getNotices($offset, $limit, $since_id, $before_id, $since);
453
        }
454
    }
455

456
    function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE, $own=false)
Evan Prodromou's avatar
Evan Prodromou committed
457
    {
458
        $ids = Fave::stream($this->id, $offset, $limit, $own);
Evan Prodromou's avatar
Evan Prodromou committed
459
        return Notice::getStreamByIds($ids);
460
    }
461

Evan Prodromou's avatar
Evan Prodromou committed
462 463
    function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
    {
Evan Prodromou's avatar
Evan Prodromou committed
464
        $ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false);
465

Evan Prodromou's avatar
Evan Prodromou committed
466
        return Notice::getStreamByIds($ids);
467 468 469 470
    }

    function noticeInbox($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
    {
Evan Prodromou's avatar
Evan Prodromou committed
471
        $ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true);
472

Evan Prodromou's avatar
Evan Prodromou committed
473
        return Notice::getStreamByIds($ids);
474
    }
475

Evan Prodromou's avatar
Evan Prodromou committed
476 477
    function blowFavesCache()
    {
478 479
        $cache = common_memcache();
        if ($cache) {
480
            // Faves don't happen chronologically, so we need to blow
Evan Prodromou's avatar
Evan Prodromou committed
481
            // ;last cache, too
Evan Prodromou's avatar
Evan Prodromou committed
482 483
            $cache->delete(common_cache_key('fave:ids_by_user:'.$this->id));
            $cache->delete(common_cache_key('fave:ids_by_user:'.$this->id.';last'));
484 485
            $cache->delete(common_cache_key('fave:ids_by_user_own:'.$this->id));
            $cache->delete(common_cache_key('fave:ids_by_user_own:'.$this->id.';last'));
486
        }
487 488
        $profile = $this->getProfile();
        $profile->blowFaveCount();
489
    }
490

Evan Prodromou's avatar
Evan Prodromou committed
491 492
    function getSelfTags()
    {
493 494
        return Profile_tag::getTags($this->id, $this->id);
    }
495

Evan Prodromou's avatar
Evan Prodromou committed
496 497
    function setSelfTags($newtags)
    {
498 499
        return Profile_tag::setTags($this->id, $this->id, $newtags);
    }
Evan Prodromou's avatar
Evan Prodromou committed
500

501 502
    function block($other)
    {
Evan Prodromou's avatar
Evan Prodromou committed
503
        // Add a new block record
Evan Prodromou's avatar
Evan Prodromou committed
504 505 506

        $block = new Profile_block();

Evan Prodromou's avatar
Evan Prodromou committed
507
        // Begin a transaction
Evan Prodromou's avatar
Evan Prodromou committed
508 509 510 511 512 513 514 515 516 517 518 519 520

        $block->query('BEGIN');

        $block->blocker = $this->id;
        $block->blocked = $other->id;

        $result = $block->insert();

        if (!$result) {
            common_log_db_error($block, 'INSERT', __FILE__);
            return false;
        }

Evan Prodromou's avatar
Evan Prodromou committed
521
        // Cancel their subscription, if it exists
Evan Prodromou's avatar
Evan Prodromou committed
522

523 524
        $sub = Subscription::pkeyGet(array('subscriber' => $other->id,
                                           'subscribed' => $this->id));
Evan Prodromou's avatar
Evan Prodromou committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538

        if ($sub) {
            $result = $sub->delete();
            if (!$result) {
                common_log_db_error($sub, 'DELETE', __FILE__);
                return false;
            }
        }

        $block->query('COMMIT');

        return true;
    }

539 540
    function unblock($other)
    {
Evan Prodromou's avatar
Evan Prodromou committed
541
        // Get the block record
Evan Prodromou's avatar
Evan Prodromou committed
542

543
        $block = Profile_block::get($this->id, $other->id);
Evan Prodromou's avatar
Evan Prodromou committed
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

        if (!$block) {
            return false;
        }

        $result = $block->delete();

        if (!$result) {
            common_log_db_error($block, 'DELETE', __FILE__);
            return false;
        }

        return true;
    }

559 560
    function isMember($group)
    {
561 562
        $profile = $this->getProfile();
        return $profile->isMember($group);
563 564 565 566
    }

    function isAdmin($group)
    {
567 568
        $profile = $this->getProfile();
        return $profile->isAdmin($group);
569
    }
570

Evan Prodromou's avatar
Evan Prodromou committed
571
    function getGroups($offset=0, $limit=null)
572 573 574 575 576 577 578 579
    {
        $qry =
          'SELECT user_group.* ' .
          'FROM user_group JOIN group_member '.
          'ON user_group.id = group_member.group_id ' .
          'WHERE group_member.profile_id = %d ' .
          'ORDER BY group_member.created DESC ';

Evan Prodromou's avatar
Evan Prodromou committed
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
        if ($offset) {
            if (common_config('db','type') == 'pgsql') {
                $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
            } else {
                $qry .= ' LIMIT ' . $offset . ', ' . $limit;
            }
        }

        $groups = new User_group();

        $cnt = $groups->query(sprintf($qry, $this->id));

        return $groups;
    }

    function getSubscriptions($offset=0, $limit=null)
    {
597 598 599
        $profile = $this->getProfile();
        assert(!empty($profile));
        return $profile->getSubscriptions($offset, $limit);
Evan Prodromou's avatar
Evan Prodromou committed
600 601 602 603
    }

    function getSubscribers($offset=0, $limit=null)
    {
604 605 606
        $profile = $this->getProfile();
        assert(!empty($profile));
        return $profile->getSubscribers($offset, $limit);
607
    }
608 609 610 611 612 613 614 615 616 617

    function getTaggedSubscribers($tag, $offset=0, $limit=null)
    {
        $qry =
          'SELECT profile.* ' .
          'FROM profile JOIN subscription ' .
          'ON profile.id = subscription.subscriber ' .
          'JOIN profile_tag ON (profile_tag.tagged = subscription.subscriber ' .
          'AND profile_tag.tagger = subscription.subscribed) ' .
          'WHERE subscription.subscribed = %d ' .
618
          "AND profile_tag.tag = '%s' " .
619 620 621 622
          'AND subscription.subscribed != subscription.subscriber ' .
          'ORDER BY subscription.created DESC ';

        if ($offset) {
623
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
        }

        $profile = new Profile();

        $cnt = $profile->query(sprintf($qry, $this->id, $tag));

        return $profile;
    }

    function getTaggedSubscriptions($tag, $offset=0, $limit=null)
    {
        $qry =
          'SELECT profile.* ' .
          'FROM profile JOIN subscription ' .
          'ON profile.id = subscription.subscribed ' .
          'JOIN profile_tag on (profile_tag.tagged = subscription.subscribed ' .
          'AND profile_tag.tagger = subscription.subscriber) ' .
          'WHERE subscription.subscriber = %d ' .
642
          "AND profile_tag.tag = '%s' " .
643 644 645
          'AND subscription.subscribed != subscription.subscriber ' .
          'ORDER BY subscription.created DESC ';

646
        $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
647 648 649 650 651 652 653

        $profile = new Profile();

        $profile->query(sprintf($qry, $this->id, $tag));

        return $profile;
    }
654

Evan Prodromou's avatar
Evan Prodromou committed
655 656 657 658
    function getDesign()
    {
        return Design::staticGet('id', $this->design_id);
    }
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702

    function hasRole($name)
    {
        $role = User_role::pkeyGet(array('user_id' => $this->id,
                                         'role' => $name));
        return (!empty($role));
    }

    function grantRole($name)
    {
        $role = new User_role();

        $role->user_id = $this->id;
        $role->role    = $name;
        $role->created = common_sql_now();

        $result = $role->insert();

        if (!$result) {
            common_log_db_error($role, 'INSERT', __FILE__);
            return false;
        }

        return true;
    }

    function revokeRole($name)
    {
        $role = User_role::pkeyGet(array('user_id' => $this->id,
                                         'role' => $name));

        if (empty($role)) {
            throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; does not exist.');
        }

        $result = $role->delete();

        if (!$result) {
            common_log_db_error($role, 'DELETE', __FILE__);
            throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; database error.');
        }

        return true;
    }
Evan Prodromou's avatar
Evan Prodromou committed
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717

    /**
     * Does this user have the right to do X?
     *
     * With our role-based authorization, this is merely a lookup for whether the user
     * has a particular role. The implementation currently uses a switch statement
     * to determine if the user has the pre-defined role to exercise the right. Future
     * implementations may allow per-site roles, and different mappings of roles to rights.
     *
     * @param $right string Name of the right, usually a constant in class Right
     * @return boolean whether the user has the right in question
     */

    function hasRight($right)
    {
718 719 720 721
        $result = false;
        if (Event::handle('UserRightsCheck', array($this, $right, &$result))) {
            switch ($right)
            {
722 723
            case Right::DELETEOTHERSNOTICE:
                $result = $this->hasRole(User_role::MODERATOR);
724
                break;
725 726 727
            case Right::CONFIGURESITE:
                $result = $this->hasRole(User_role::ADMINISTRATOR);
            default:
728 729 730
                $result = false;
                break;
            }
Evan Prodromou's avatar
Evan Prodromou committed
731
        }
732
        return $result;
Evan Prodromou's avatar
Evan Prodromou committed
733
    }
734 735 736 737

    function delete()
    {
        $profile = $this->getProfile();
738 739 740
        if ($profile) {
            $profile->delete();
        }
741 742 743 744 745 746

        $related = array('Fave',
                         'Confirm_address',
                         'Remember_me',
                         'Foreign_link',
                         'Invitation',
Evan Prodromou's avatar
Evan Prodromou committed
747
                         'Notice_inbox',
748
                         );
749
        Event::handle('UserDeleteRelated', array($this, &$related));
750 751 752 753 754 755 756 757

        foreach ($related as $cls) {
            $inst = new $cls();
            $inst->user_id = $this->id;
            $inst->delete();
        }

        $this->_deleteTags();
Evan Prodromou's avatar
Evan Prodromou committed
758
        $this->_deleteBlocks();
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776

        parent::delete();
    }

    function _deleteTags()
    {
        $tag = new Profile_tag();
        $tag->tagger = $this->id;
        $tag->delete();
    }

    function _deleteBlocks()
    {
        $block = new Profile_block();
        $block->blocker = $this->id;
        $block->delete();
        // XXX delete group block? Reset blocker?
    }
Evan Prodromou's avatar
Evan Prodromou committed
777
}