/** * Create a status update for a member * * @param array [Array of member data for member updating their status - will use ->getAuthor() if null] * @param array [Array of status information OR status ID OR uses $this->_internalData['StatusData'] if none] * @return array Reply information */ public function reply($author = null, $status = null) { $author = $author === null ? $this->getAuthor() : $author; $status = $status === null ? $this->_internalData['StatusData'] : (is_array($status) ? $status : $this->_loadStatus($status)); $data = array(); if ($this->canReply($author, $status, $status)) { if ($this->getContent() and $status['status_id']) { $data = array('reply_status_id' => $status['status_id'], 'reply_member_id' => $author['member_id'], 'reply_date' => time(), 'reply_content' => $this->_cleanContent($this->getContent())); /* Data Hook Location */ IPSLib::doDataHooks($data, 'statusCommentNew'); $this->DB->insert('member_status_replies', $data); $data['reply_id'] = $this->DB->getInsertId(); $this->_recordAction('reply', $author, $status, $data); $this->rebuildStatus($status); $this->rebuildOwnerLatest($author); $this->_sendNotification($author, $status, $data); } return $data; } return FALSE; }
/** * Import and parse an iCalendar feed * * @param string $content Feed content * @param int $member_id Member to save events under * @param int $feed_id Feed id * @return mixed False on failure, otherwise an array with keys 'skipped' and 'imported' */ public function import($content, $member_id = 0, $feed_id = 0) { //----------------------------------------- // Init //----------------------------------------- $this->lang->loadLanguageFile(array('admin_calendar'), 'calendar'); //----------------------------------------- // Error checking //----------------------------------------- if (!$content) { $this->_error = $this->lang->words['icali_nocontent']; return; } $_raw = preg_replace("#(\n\r|\r|\n){1,}#", "\n", $content); $_raw = explode("\n", $_raw); if (!count($_raw)) { $this->_error = $this->lang->words['icali_nocontent']; return; } if ($_raw[0] != 'BEGIN:VCALENDAR') { $this->_error = $this->lang->words['icali_badcontent']; return; } $this->_rawIcsData = $_raw; //----------------------------------------- // Loop and start parsing //----------------------------------------- foreach ($this->_rawIcsData as $k => $v) { $line = explode(':', $v); switch ($line[0]) { case 'BEGIN': $this->_parseBeginBlock($line[1], $k); break; /* Unsupported at this time */ /* Unsupported at this time */ case 'CALSCALE': case 'METHOD': case 'X-WR-TIMEZONE': case 'X-WR-RELCALID': default: break; } } //----------------------------------------- // Process raw ICS data now //----------------------------------------- if (count($this->_parsedIcsData)) { $this->_parsedIcsData = $this->_convertToGmt($this->_parsedIcsData); } //----------------------------------------- // And loop over results to insert //----------------------------------------- $_imported = 0; $_skipped = 0; // Leave this here - useful for debugging //print_r($this->_parsedIcsData);exit; if (count($this->_parsedIcsData)) { //----------------------------------------- // Get member data //----------------------------------------- $_member = IPSMember::load($member_id); if (!$_member) { $this->_error = $this->lang->words['icali_nomember']; return false; } //----------------------------------------- // Get like class for notifications //----------------------------------------- require_once IPS_ROOT_PATH . 'sources/classes/like/composite.php'; /*noLibHook*/ $_like = classes_like::bootstrap('calendar', 'calendars'); //----------------------------------------- // Loop over the events //----------------------------------------- foreach ($this->_parsedIcsData['events'] as $event) { $event['uid'] = $event['uid'] ? $event['uid'] : md5(implode(',', $event)); $event_unix_from = $event['start']['gmt_ts']; $event_unix_to = $event['end']['gmt_ts']; $event_all_day = $event['start']['type'] == 'DATE' ? 1 : 0; //----------------------------------------- // End dates are "exclusive" in iCalendar format, meaning // they are actually the day ahead. // @link http://microformats.org/wiki/dtend-issue //----------------------------------------- if ($event_unix_to and $event['end']['type'] == 'DATE') { $event_unix_to -= 86400; } //----------------------------------------- // If end date is same as start date, it's a single day event //----------------------------------------- if ($event_unix_from == $event_unix_to) { $event_unix_to = 0; } //----------------------------------------- // If no end date, but we have a duration, calculate end date //----------------------------------------- if (!$event_unix_to and $event['duration']) { preg_match("#(\\d+?)H#is", $event['duration'], $match); $hour = $match[1] ? $match[1] : 0; preg_match("#(\\d+?)M#is", $event['duration'], $match); $minute = $match[1] ? $match[1] : 0; preg_match("#(\\d+?)S#is", $event['duration'], $match); $second = $match[1] ? $match[1] : 0; $event_unix_to = $event_unix_from + $hour * 3600 + $minute * 60 + $second; } //----------------------------------------- // Recurring... //----------------------------------------- $recurring = 0; if (isset($event['recurr']['FREQ'])) { if ($event['recurr']['FREQ'] == 'MONTHLY' and $event['recurr']['INTERVAL'] == 12) { $event['recurr']['FREQ'] = 'YEARLY'; } switch ($event['recurr']['FREQ']) { case 'WEEKLY': $recurring = 1; break; case 'MONTHLY': $recurring = 2; break; case 'YEARLY': $recurring = 3; break; } $event_unix_to = $event['recurr']['until_ts'] ? $event['recurr']['until_ts'] : time() + 86400 * 365 * 10; } //----------------------------------------- // Adjust timestamps if all day event //----------------------------------------- if ($event_all_day) { $event_unix_from = gmmktime(0, 0, 0, gmstrftime('%m', $event_unix_from), gmstrftime('%d', $event_unix_from), gmstrftime('%Y', $event_unix_from)); $event_unix_to = $event_unix_to ? gmmktime(0, 0, 0, gmstrftime('%m', $event_unix_to), gmstrftime('%d', $event_unix_to), gmstrftime('%Y', $event_unix_to)) : 0; } //----------------------------------------- // If we are missing crucial data, skip //----------------------------------------- if (!($event['description'] or $event['summary']) or !$event_unix_from) { $_skipped++; continue; } //----------------------------------------- // Skip previously imported events //----------------------------------------- if ($event['uid']) { $_check = $this->DB->buildAndFetch(array('select' => 'import_id', 'from' => 'cal_import_map', 'where' => "import_guid='" . $this->DB->addSlashes($event['uid']) . "'")); if ($_check['import_id']) { $_skipped++; continue; } } //----------------------------------------- // Format array for storage //----------------------------------------- $_eventData = array('event_calendar_id' => $this->calendar['cal_id'], 'event_member_id' => $_member['member_id'], 'event_content' => $event['description'] ? nl2br($event['description']) : $event['summary'], 'event_title' => $event['summary'] ? $event['summary'] : IPSText::truncate($event['description'], 100), 'event_title_seo' => IPSText::makeSeoTitle($event['summary']), 'event_smilies' => 1, 'event_comments' => 0, 'event_rsvp' => count($event['attendee']) ? 1 : 0, 'event_perms' => '*', 'event_private' => 0, 'event_approved' => 1, 'event_saved' => $event['created'] ? $event['created'] : time(), 'event_lastupdated' => $event['last_modified'] ? $event['last_modified'] : ($event['created'] ? $event['created'] : time()), 'event_recurring' => $recurring, 'event_start_date' => strftime("%Y-%m-%d %H:%M:00", $event_unix_from), 'event_end_date' => $event_unix_to ? strftime("%Y-%m-%d %H:%M:00", $event_unix_to) : 0, 'event_post_key' => md5(uniqid(microtime(), true)), 'event_sequence' => intval($event['sequence']), 'event_all_day' => $event_all_day); //----------------------------------------- // Data hooks //----------------------------------------- IPSLib::doDataHooks($_eventData, 'calendarAddEvent'); //----------------------------------------- // Insert //----------------------------------------- $this->DB->insert('cal_events', $_eventData); $event_id = $this->DB->getInsertId(); $_imported++; //----------------------------------------- // Insert mapping //----------------------------------------- $this->DB->insert('cal_import_map', array('import_feed_id' => $feed_id, 'import_event_id' => $event_id, 'import_guid' => $event['uid'])); //----------------------------------------- // If we have attendees that are members, insert them //----------------------------------------- if (isset($event['attendee']) and count($event['attendee'])) { foreach ($event['attendee'] as $attendee) { if ($attendee['email']) { $_loadedMember = IPSMember::load($attendee['email']); if ($_loadedMember['member_id']) { $this->DB->insert('cal_event_rsvp', array('rsvp_member_id' => $_loadedMember['member_id'], 'rsvp_event_id' => $event_id, 'rsvp_date' => time())); } } } } //----------------------------------------- // Send notifications //----------------------------------------- $_url = $this->registry->output->buildSEOUrl('app=calendar&module=calendar&section=view&do=showevent&event_id=' . $event_id, 'public', $_eventData['event_title_seo'], 'cal_event'); $_like->sendNotifications($_eventData['event_calendar_id'], array('immediate', 'offline'), array('notification_key' => 'new_event', 'notification_url' => $_url, 'email_template' => 'add_event_follow', 'email_subject' => sprintf($this->lang->words['add_event_follow_subject'], $_url, $_eventData['event_title']), 'build_message_array' => array('NAME' => '-member:members_display_name-', 'AUTHOR' => $_member['members_display_name'], 'TITLE' => $_eventData['event_title'], 'URL' => $_url))); } } //----------------------------------------- // Rebuild cache //----------------------------------------- $this->cache->rebuildCache('calendar_events', 'calendar'); //----------------------------------------- // Return //----------------------------------------- return array('skipped' => $_skipped, 'imported' => $_imported); }
/** * Action: Issue Warning */ public function save() { //----------------------------------------- // Init //----------------------------------------- $points = 0; $mq = 0; $mq_unit = 'd'; $rpa = 0; $rpa_unit = 'd'; $suspend = 0; $suspend_unit = 'd'; $banGroup = 0; $removePoints = 0; $removePointsUnit = 'd'; //----------------------------------------- // Validate //----------------------------------------- $errors = array(); if ($this->request['reason'] === '') { /* No reason selected */ $errors['reason'] = $this->lang->words['warnings_err_reason']; } else { $reason = intval($this->request['reason']); /* "Other" reason selected */ if (!$reason) { /* Check we're actually allowed to use it */ if (!$this->memberData['g_access_cp'] and !$this->settings['warnings_enable_other']) { /* Nope */ $errors['reason'] = $this->lang->words['warnings_err_reason']; } else { /* If we select "Other", we determine the number of points and when they expire */ $points = floatval($this->request['points']); $removePoints = intval($this->request['remove']); $removePointsUnit = $this->request['remove_unit'] == 'h' ? 'h' : 'd'; } } else { $reason = $this->reasons[$reason]; /* Check it's valid */ if (!$reason['wr_id']) { /* Nope */ $errors['reason'] = $this->lang->words['warnings_err_reason']; } else { /* Can we override the number of points for this reason? */ if ($this->memberData['g_access_cp'] or $reason['wr_points_override']) { // Yes, get value from input $points = floatval($this->request['points']); } else { // No, take whatever the reason has set $points = $reason['wr_points']; } /* Can we override when the points expire? */ if ($this->memberData['g_access_cp'] or $reason['wr_remove_override']) { // Yes, get value from input $removePoints = intval($this->request['remove']); $removePointsUnit = $this->request['remove_unit'] == 'h' ? 'h' : 'd'; } else { // No, take whatever the reason has set $removePoints = intval($reason['wr_remove']); $removePointsUnit = $reason['wr_remove_unit']; } } $reason = $reason['wr_id']; } /* Now let's get the action */ $newPointLevel = floatval($this->_member['warn_level'] + $points); $action = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'members_warn_actions', 'where' => "wa_points<={$newPointLevel}", 'order' => 'wa_points DESC', 'limit' => 1)); if ($action) { /* We have an action. Can we override it's punishment? */ if ($action['wa_override']) { // Yes, get values from input $mq = $this->request['mq_perm'] ? -1 : intval($this->request['mq']); $mq_unit = $this->request['mq_unit']; $rpa = $this->request['rpa_perm'] ? -1 : intval($this->request['rpa']); $rpa_unit = $this->request['rpa_unit']; $suspend = $this->request['suspend_perm'] ? -1 : intval($this->request['suspend']); $suspend_unit = $this->request['suspend_unit']; $banGroup = $this->request['ban_group'] ? intval($this->request['ban_group_id']) : 0; } else { // No, do whatever the action says $mq = intval($action['wa_mq']); $mq_unit = $action['wa_mq_unit']; $rpa = intval($action['wa_rpa']); $rpa_unit = $action['wa_rpa_unit']; $suspend = intval($action['wa_suspend']); $suspend_unit = $action['wa_suspend_unit']; $banGroup = intval($action['wa_ban_group']); } } else { /* We don't have an action - are we allowed to give a custom punishment? */ if ($this->memberData['g_access_cp'] or $this->settings['warning_custom_noaction']) { // Yes, get values from input $mq = $this->request['mq_perm'] ? -1 : intval($this->request['mq']); $mq_unit = $this->request['mq_unit']; $rpa = $this->request['rpa_perm'] ? -1 : intval($this->request['rpa']); $rpa_unit = $this->request['rpa_unit']; $suspend = $this->request['suspend_perm'] ? -1 : intval($this->request['suspend']); $suspend_unit = $this->request['suspend_unit']; $banGroup = $this->request['ban_group'] ? intval($this->request['ban_group_id']) : 0; } else { // We're not allowed to give a punishment so this is a verbal warning only. // The values we set earlier during init are fine } } } if (!empty($errors)) { return $this->form($errors); } //----------------------------------------- // Parse //----------------------------------------- $classToLoad = IPSLib::loadLibrary(IPS_ROOT_PATH . 'sources/classes/editor/composite.php', 'classes_editor_composite'); $editor = new $classToLoad(); $noteForMember = $editor->process($_POST['note_member']); $noteForMods = $editor->process($_POST['note_mods']); //----------------------------------------- // Save Log //----------------------------------------- /* If our points are going to expire, woprk out exactly when */ $expireDate = 0; if ($removePoints) { IPSTime::setTimestamp(time()); if ($removePointsUnit == 'h') { IPSTime::add_hours($removePoints); } else { IPSTime::add_days($removePoints); } $expireDate = IPSTime::getTimestamp(); } /* Log */ $warning = array('wl_member' => $this->_member['member_id'], 'wl_moderator' => $this->memberData['member_id'], 'wl_date' => time(), 'wl_reason' => $reason, 'wl_points' => $points, 'wl_note_member' => $noteForMember, 'wl_note_mods' => $noteForMods, 'wl_mq' => $mq, 'wl_mq_unit' => $mq_unit, 'wl_rpa' => $rpa, 'wl_rpa_unit' => $rpa_unit, 'wl_suspend' => $suspend, 'wl_suspend_unit' => $suspend_unit, 'wl_ban_group' => $banGroup, 'wl_expire' => $removePoints, 'wl_expire_unit' => $removePointsUnit, 'wl_acknowledged' => $this->settings['warnings_acknowledge'] ? 0 : 1, 'wl_content_app' => trim($this->request['from_app']), 'wl_content_id1' => $this->request['from_id1'], 'wl_content_id2' => $this->request['from_id2'], 'wl_expire_date' => $expireDate); /* Data Hook Location */ $warning['actionData'] = $action; $warning['reasonsData'] = $this->reasons; IPSLib::doDataHooks($warning, 'memberWarningPre'); unset($warning['actionData'], $warning['reasonsData']); $this->DB->insert('members_warn_logs', $warning); $warning['wl_id'] = $this->DB->getInsertId(); /* Data Hook Location */ $warning['actionData'] = $action; $warning['reasonsData'] = $this->reasons; IPSLib::doDataHooks($warning, 'memberWarningPost'); unset($warning['actionData'], $warning['reasonsData']); //----------------------------------------- // Actually do it //----------------------------------------- $update = array(); /* Add Points */ if ($points) { $update['warn_level'] = $this->_member['warn_level'] + $points; } /* Set Punishments */ if ($mq) { $update['mod_posts'] = $mq == -1 ? 1 : IPSMember::processBanEntry(array('unit' => $mq_unit, 'timespan' => $mq)); } if ($rpa) { $update['restrict_post'] = $rpa == -1 ? 1 : IPSMember::processBanEntry(array('unit' => $rpa_unit, 'timespan' => $rpa)); } if ($suspend) { if ($suspend == -1) { $update['member_banned'] = 1; } else { $update['temp_ban'] = IPSMember::processBanEntry(array('unit' => $suspend_unit, 'timespan' => $suspend)); } } if ($banGroup > 0) { if (!$this->caches['group_cache'][$banGroup]['g_access_cp'] and !$this->caches['group_cache'][$banGroup]['g_is_supmod'] and $banGroup != $this->settings['guest_group']) { $update['member_group_id'] = $banGroup; } } if ($this->settings['warnings_acknowledge']) { $update['unacknowledged_warnings'] = 1; } /* Save */ if (!empty($update)) { IPSMember::save($this->_member['member_id'], array('core' => $update)); } //----------------------------------------- // Work out where this warning came from //----------------------------------------- if ($warning['wl_content_app'] and IPSLib::appIsInstalled($warning['wl_content_app'])) { $file = IPSLib::getAppDir($warning['wl_content_app']) . '/extensions/warnings.php'; if (is_file($file)) { $classToLoad = IPSLib::loadLibrary($file, 'warnings_' . $warning['wl_content_app'], $warning['wl_content_app']); if (class_exists($classToLoad) and method_exists($classToLoad, 'getContentUrl')) { $object = new $classToLoad(); $content = $object->getContentUrl($warning); } } } //----------------------------------------- // Send notifications //----------------------------------------- /* Init */ $classToLoad = IPSLib::loadLibrary(IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications'); $notifyLibrary = new $classToLoad($this->registry); /* Send to member being warned */ if ($this->settings['warnings_acknowledge'] or $noteForMember) { try { $notifyLibrary->setMember($this->_member); $notifyLibrary->setFrom($this->memberData); $notifyLibrary->setNotificationKey('warning'); $notifyLibrary->setNotificationUrl("app=members&module=profile§ion=warnings&member={$this->_member['member_id']}"); $notifyLibrary->setNotificationTitle(sprintf($this->lang->words['warnings_notify'], $this->registry->output->buildUrl("app=members&module=profile§ion=warnings&member={$this->_member['member_id']}"))); $notifyLibrary->setNotificationText(sprintf($this->lang->words['warnings_notify_text'], $this->_member['members_display_name'], $this->memberData['members_display_name'], $reason ? $this->reasons[$reason]['wr_name'] : $this->lang->words['warnings_reasons_other'], $noteForMember ? sprintf($this->lang->words['warnings_notify_member_note'], $noteForMember) : '', $this->settings['warn_show_own'] ? sprintf($this->lang->words['warnings_notify_view_link'], $this->registry->output->buildUrl("app=members&module=profile§ion=warnings&member={$this->_member['member_id']}")) : '')); $notifyLibrary->sendNotification(); } catch (Exception $e) { } } /* And all mods that can warn and are super_mods (split this up because of: @link http://community.invisionpower.com/tracker/issue-36960-bad-warn-query/ */ $mods = array(); $mids = array(); $gids = array(); $canWarnMids = array(); $canWarnGids = array(); $this->DB->build(array('select' => 'member_id, allow_warn', 'from' => 'moderators', 'where' => 'is_group=0')); $this->DB->execute(); while ($row = $this->DB->fetch()) { $mids[$row['member_id']] = $row['member_id']; if ($row['allow_warn']) { $canWarnMids[] = $row['member_id']; } } $this->DB->build(array('select' => 'group_id', 'from' => 'moderators', 'where' => 'is_group=1 AND allow_warn=1')); $this->DB->execute(); while ($row = $this->DB->fetch()) { $gids[] = $row['group_id']; $canWarnGids[] = $row['group_id']; } foreach ($this->caches['group_cache'] as $id => $row) { if ($row['g_is_supmod']) { $gids[] = $row['g_id']; } } /* Limit this because it could go a bit wrong innit */ if (count($gids)) { $this->DB->build(array('select' => 'member_id', 'from' => 'members', 'where' => 'member_group_id IN (' . implode(',', $gids) . ')', 'limit' => array(0, 750))); $this->DB->execute(); while ($row = $this->DB->fetch()) { $mids[$row['member_id']] = $row['member_id']; } } $_mods = IPSMember::load($mids, 'all'); if (count($_mods)) { foreach ($_mods as $id => $row) { if ($row['member_id'] == $this->memberData['member_id']) { continue; } if ($row['g_is_supmod'] or in_array($row['member_id'], $canWarnMids) or in_array($row['member_group_id'], $canWarnGids)) { $mods[$row['member_id']] = $row; } } } if (count($mods)) { $notifyLibrary = new $classToLoad($this->registry); $notifyLibrary->setMultipleRecipients($mods); $notifyLibrary->setFrom($this->memberData); $notifyLibrary->setNotificationKey('warning_mods'); $notifyLibrary->setNotificationUrl("app=members&module=profile§ion=warnings&member={$this->_member['member_id']}"); $notifyLibrary->setNotificationTitle(sprintf($this->lang->words['warnings_notify_mod'], $this->_member['members_display_name'], $this->registry->output->buildUrl("app=members&module=profile§ion=warnings&member={$this->_member['member_id']}"), $this->memberData['members_display_name'])); $notifyLibrary->setNotificationText(sprintf($this->lang->words['warnings_notify_text_mod'], $this->_member['members_display_name'], $this->memberData['members_display_name'], $this->registry->output->buildUrl("app=members&module=profile§ion=warnings&member={$this->_member['member_id']}"))); try { $notifyLibrary->sendNotification(); } catch (Exception $e) { } } //----------------------------------------- // Boink //----------------------------------------- if (empty($content['url'])) { $this->registry->getClass('output')->redirectScreen($this->lang->words['warnings_done'], $this->settings['base_url'] . 'app=members&module=profile&section=warnings&member=' . $this->_member['member_id']); } else { $this->registry->getClass('output')->redirectScreen($this->lang->words['warnings_done'], $content['url']); } }
/** * Update forum's last post information * * @param array $topic * @param string $type * @return @e void */ protected function updateForumAndStats($topic, $type = 'new') { $moderated = 0; $stat_cache = $this->registry->cache()->getCache('stats'); $forum_data = $this->getForumData(); //----------------------------------------- // Moderated? //----------------------------------------- $moderate = 0; if ($this->getPublished() === false) { $moderate = 1; } //----------------------------------------- // Add to forum's last post? //----------------------------------------- if (!$moderate) { if ($topic['approved']) { $dbs = array('last_title' => $topic['title'], 'seo_last_title' => IPSText::makeSeoTitle($topic['title']), 'last_id' => $topic['tid'], 'last_post' => IPS_UNIX_TIME_NOW, 'last_poster_name' => $this->getAuthor('member_id') ? $this->getAuthor('members_display_name') : $this->request['UserName'], 'seo_last_name' => IPSText::makeSeoTitle($this->getAuthor('member_id') ? $this->getAuthor('members_display_name') : $this->request['UserName']), 'last_poster_id' => $this->getAuthor('member_id'), 'last_x_topic_ids' => $this->registry->class_forums->lastXFreeze($this->registry->class_forums->buildLastXTopicIds($forum_data['id'], FALSE))); if ($type == 'new') { $stat_cache['total_topics']++; $forum_data['topics'] = intval($forum_data['topics']); $dbs['topics'] = ++$forum_data['topics']; $dbs['newest_id'] = $topic['tid']; $dbs['newest_title'] = $topic['title']; } else { $stat_cache['total_replies']++; $forum_data['posts'] = intval($forum_data['posts']); $dbs['posts'] = ++$forum_data['posts']; } } } else { if ($type == 'new') { $forum_data['queued_topics'] = intval($forum_data['queued_topics']); $dbs['queued_topics'] = ++$forum_data['queued_topics']; } else { $forum_data['queued_posts'] = intval($forum_data['queued_posts']); $dbs['queued_posts'] = ++$forum_data['queued_posts']; } } //----------------------------------------- // Merging posts? // Don't update counter //----------------------------------------- if ($this->_isMergingPosts) { unset($dbs['posts']); unset($dbs['queued_posts']); $stat_cache['total_replies'] -= 1; } //----------------------------------------- // Update //----------------------------------------- if (is_array($dbs) and count($dbs)) { $this->DB->setDataType(array('last_poster_name', 'seo_last_name', 'seo_last_title', 'last_title'), 'string'); /* Data Hook Location */ IPSLib::doDataHooks($dbs, 'updateForumLastPostData'); $this->DB->update('forums', $dbs, "id=" . intval($forum_data['id'])); } //----------------------------------------- // Update forum cache //----------------------------------------- //$this->registry->getClass('class_forums')->updateForumCache(); $this->registry->cache()->setCache('stats', $stat_cache, array('array' => 1, 'donow' => 0)); }
/** * Sends a new personal message. Very simple. * * @param int TO Member ID * @param int FROM Member ID * @param array Array of InviteUser Names (display name) * @param string Message Title * @param string Message Content * @param array Options array[ 'isSystem' (if true, then user will have no record of sending this PM) postKey, 'isDraft', 'sendMode' (invite/copy), 'topicID' ] If a topicID is passed, it's presumed that it was a draft.... * @return mixed TRUE or FALSE or Exception * * <code> * Exception Codes: * TOPIC_ID_NOT_EXISTS: Topic ID does not exist (re-sending a draft) * NOT_ALL_INVITE_USERS_EXIST: Not all invite users exist (check $this->exceptionData for a list of names) * NOT_ALL_INVITE_USERS_CAN_PM: Not all invite users can PM (check $this->exceptionData for a list of names) * INVITE_USERS_BLOCKED: Some invite users have been blocked (check $this->exceptionData for a list of names) * TO_USER_DOES_NOT_EXIST: The 'to' user ID does not exist * FROM_USER_DOES_NOT_EXIST: The 'from' user ID does not exist * TO_USER_CANNOT_USE_PM: The 'to' user does not have access to PM system * TO_USER_FULL: The 'to' user cannot accept any more PMs (inbox full) * FROM_USER_BLOCKED: The 'from' user has been blocked by the 'to' user * CANNOT_SAVE_TO_SENT_FOLDER: The 'from' user does not have space to store a copy of the message in their sent folder * MSG_TITLE_EMPTY: The 'msgTitle' variable is empty * MSG_CONTENT_EMPTY: The 'msgContent' varable is empty * CANT_SEND_TO_SELF: The main recipient and sender are the same * CANT_INVITE_SELF: The sender is in the invite list * CANT_INVITE_RECIPIENT: The main recipient is in the invite list * FLOOD_STOP Flood control will not allow this message to send * </code> */ public function sendNewPersonalTopic($toMemberID, $fromMemberID, $inviteUsers, $msgTitle, $msgContent, $options = array()) { //----------------------------------------- // INIT //----------------------------------------- $toMemberData = array(); $fromMemberData = array(); $inviteUsersData = array(); $isDraft = $options['isDraft'] ? TRUE : FALSE; $isCopyTo = $options['sendMode'] == 'copy' ? TRUE : FALSE; $isSystem = $options['isSystem'] === TRUE || $options['isSystem'] == 1 ? 1 : 0; $options['postKey'] = $options['postKey'] ? $options['postKey'] : md5(microtime()); /* Set up force message*/ $this->forceMessageToSend = $this->forceMessageToSend ? $this->forceMessageToSend : ($options['forcePm'] ? TRUE : FALSE); //----------------------------------------- // Check content //----------------------------------------- if ($toMemberID == $fromMemberID) { throw new Exception('CANT_SEND_TO_SELF'); } if (!$msgTitle) { throw new Exception('MSG_TITLE_EMPTY'); } if (!$msgContent) { throw new Exception('MSG_CONTENT_EMPTY'); } //----------------------------------------- // Format content //----------------------------------------- try { $_originalMessageContent = $msgContent; $msgContent = $this->_formatMessageForSaving($msgContent); } catch (Exception $error) { throw new Exception($error->getMessage()); } //----------------------------------------- // First off, load the to and from members //----------------------------------------- $_members = IPSMember::load(array($toMemberID, $fromMemberID), 'groups,extendedProfile'); $toMemberData = $this->_setMaxMessages($_members[$toMemberID]); $fromMemberData = $this->_setMaxMessages($_members[$fromMemberID]); if (empty($toMemberData['member_id']) and $this->forceMessageToSend !== TRUE) { throw new Exception('TO_USER_DOES_NOT_EXIST'); } if (empty($fromMemberData['member_id']) and $this->forceMessageToSend !== TRUE) { throw new Exception('FROM_USER_DOES_NOT_EXIST'); } if ($this->floodControlCheck() !== TRUE) { throw new Exception('FLOOD_STOP'); } //----------------------------------------- // Sort out invite users //----------------------------------------- if (is_array($inviteUsers) and count($inviteUsers)) { try { if ($fromMemberData['g_max_mass_pm'] > 0 or $this->forceMessageToSend === TRUE) { $inviteUsersData = $this->checkAndReturnInvitedUsers($inviteUsers); } } catch (Exception $error) { if ($this->forceMessageToSend !== TRUE) { throw new Exception($error->getMessage()); } } if (isset($inviteUsersData[$fromMemberID])) { throw new Exception('CANT_INVITE_SELF'); } if (isset($inviteUsersData[$toMemberID])) { throw new Exception('CANT_INVITE_RECIPIENT'); } } //----------------------------------------- // Can the 'to' user accept a PM? //----------------------------------------- if ($this->canUsePMSystem($toMemberData) !== TRUE) { if ($this->forceMessageToSend !== TRUE) { throw new Exception('TO_USER_CANNOT_USE_PM'); } } //----------------------------------------- // Does the 'to' user have enough space? //----------------------------------------- if ($this->withinPMQuota($toMemberData) !== TRUE) { if ($this->forceMessageToSend !== TRUE) { throw new Exception('TO_USER_FULL'); } } //----------------------------------------- // Has the 'to' use blocked us? //----------------------------------------- if (count($this->blockedByUser($fromMemberData, $toMemberData))) { if ($this->forceMessageToSend !== TRUE) { throw new Exception('FROM_USER_BLOCKED'); } } //----------------------------------------- // Is this simply a copy-to? //----------------------------------------- if ($isCopyTo === TRUE and !$isDraft) { /* Send out the main one */ $this->sendNewPersonalTopic($toMemberID, $fromMemberID, array(), $msgTitle, $_originalMessageContent, array('postKey' => $options['postKey'])); /* Send out copy-tos */ foreach ($inviteUsersData as $id => $toMember) { $_newPostKey = md5(microtime()); $_newContent = $_originalMessageContent; /* We need to duplicate the attachment record for each copy sent */ $this->DB->build(array('select' => '*', 'from' => 'attachments', 'where' => "attach_post_key='{$options['postKey']}'")); $outer = $this->DB->execute(); $idRemap = array(); while ($attachData = $this->DB->fetch($outer)) { $attachData['attach_post_key'] = $_newPostKey; $_oldAttachId = $attachData['attach_id']; unset($attachData['attach_id']); $this->DB->insert('attachments', $attachData); $idRemap[$_oldAttachId] = $this->DB->getInsertId(); } if (count($idRemap)) { foreach ($idRemap as $_oldId => $_newId) { $_newContent = str_replace('=' . $_oldId . ':', '=' . $_newId . ':', $_newContent); } } $this->sendNewPersonalTopic($toMember['member_id'], $fromMemberID, array(), $msgTitle, $_newContent, array('postKey' => $_newPostKey)); } /* Done */ return TRUE; } //----------------------------------------- // Insert the user data //----------------------------------------- $_count = count($inviteUsersData); //----------------------------------------- // Got a topic ID? //----------------------------------------- if ($options['topicID']) { /* Fetch topic data */ $_topicData = $this->fetchTopicData($options['topicID']); if (!$_topicData['mt_id'] and $this->forceMessageToSend !== TRUE) { throw new Exception('TOPIC_ID_NOT_EXISTS'); } $this->DB->setDataType('mt_title', 'string'); /* First off, update message_topics and message_posts... */ $this->DB->update('message_topics', array('mt_date' => time(), 'mt_title' => $msgTitle, 'mt_starter_id' => $fromMemberData['member_id'], 'mt_start_time' => time(), 'mt_last_post_time' => time(), 'mt_invited_members' => serialize(array_keys($inviteUsersData)), 'mt_to_count' => count(array_keys($inviteUsersData)) + 1, 'mt_to_member_id' => $toMemberData['member_id'], 'mt_is_draft' => intval($isDraft)), 'mt_id=' . $_topicData['mt_id']); /* Now the posts ... */ $this->DB->update('message_posts', array('msg_date' => time(), 'msg_topic_id' => $_topicData['mt_id'], 'msg_post' => $msgContent, 'msg_author_id' => $fromMemberData['member_id'], 'msg_is_first_post' => 1, 'msg_ip_address' => $this->member->ip_address), 'msg_id=' . $_topicData['mt_first_msg_id']); /* Delete any current user mapping as this will be sorted out below */ $this->DB->delete('message_topic_user_map', 'map_topic_id=' . $_topicData['mt_id']); /* Reset variable IDs */ $msg_topic_id = $_topicData['mt_id']; $msg_id = $_topicData['mt_first_msg_id']; } else { $_messageTopicData = array('mt_date' => time(), 'mt_title' => $msgTitle, 'mt_starter_id' => $fromMemberData['member_id'], 'mt_start_time' => IPS_UNIX_TIME_NOW, 'mt_last_post_time' => IPS_UNIX_TIME_NOW, 'mt_invited_members' => serialize(array_keys($inviteUsersData)), 'mt_to_count' => count(array_keys($inviteUsersData)) + 1, 'mt_to_member_id' => $toMemberData['member_id'], 'mt_is_draft' => $isDraft ? 1 : 0, 'mt_is_system' => $isSystem, 'mt_replies' => 0); /* Create topic entry */ $this->DB->setDataType('mt_title', 'string'); /* Data Hook Location */ IPSLib::doDataHooks($_messageTopicData, 'messengerSendTopicData'); $this->DB->insert('message_topics', $_messageTopicData); $msg_topic_id = $this->DB->getInsertId(); $_messagePostData = array('msg_date' => time(), 'msg_topic_id' => $msg_topic_id, 'msg_post' => $msgContent, 'msg_post_key' => $options['postKey'], 'msg_author_id' => $fromMemberData['member_id'], 'msg_is_first_post' => 1, 'msg_ip_address' => $this->member->ip_address); /* Data Hook Location */ IPSLib::doDataHooks($_messagePostData, 'messengerSendTopicFirstPostData'); $this->DB->insert('message_posts', $_messagePostData); $msg_id = $this->DB->getInsertId(); } //----------------------------------------- // Update with last / first msg ID //----------------------------------------- $this->DB->update('message_topics', array('mt_last_msg_id' => $msg_id, 'mt_first_msg_id' => $msg_id, 'mt_hasattach' => intval($this->_makeAttachmentsPermanent($options['postKey'], $msg_id, $msg_topic_id))), 'mt_id=' . $msg_topic_id); //----------------------------------------- // Not a draft? //----------------------------------------- if ($isDraft !== TRUE) { //----------------------------------------- // Add in 'to user' and 'from user' to the cc array //----------------------------------------- $inviteUsersData[$toMemberData['member_id']] = $toMemberData; $inviteUsersData[$fromMemberData['member_id']] = $fromMemberData; //----------------------------------------- // Loop.... //----------------------------------------- foreach ($inviteUsersData as $id => $toMember) { //----------------------------------------- // Enter the info into the DB // Target user side. //----------------------------------------- $_isStarter = $fromMemberData['member_id'] == $toMember['member_id'] ? 1 : 0; $_isSystem = ($fromMemberData['member_id'] == $toMember['member_id'] and $isSystem) ? 1 : 0; $_isActive = $_isSystem ? 0 : 1; /* Create user map entry */ $this->DB->insert('message_topic_user_map', array('map_user_id' => $toMember['member_id'], 'map_topic_id' => $msg_topic_id, 'map_folder_id' => 'myconvo', 'map_user_active' => $_isActive, 'map_is_starter' => $fromMemberData['member_id'] == $toMember['member_id'] ? 1 : 0, 'map_has_unread' => $fromMemberData['member_id'] == $toMember['member_id'] ? 0 : 1, 'map_read_time' => $fromMemberData['member_id'] == $toMember['member_id'] ? IPS_UNIX_TIME_NOW : 0, 'map_is_system' => $_isSystem, 'map_user_banned' => 0, 'map_left_time' => 0, 'map_ignore_notification' => 0, 'map_last_topic_reply' => IPS_UNIX_TIME_NOW)); //----------------------------------------- // Notifications library //----------------------------------------- if ($fromMemberData['member_id'] != $toMember['member_id']) { $classToLoad = IPSLib::loadLibrary(IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications'); $notifyLibrary = new $classToLoad($this->registry); $toMember['language'] = $toMember['language'] == "" ? IPSLib::getDefaultLanguage() : $toMember['language']; $buildMessage = array('NAME' => $toMember['members_display_name'], 'POSTER' => $fromMemberData['members_display_name'], 'TITLE' => $msgTitle, 'TEXT' => $msgContent, 'LINK' => "?app=members&module=messaging§ion=view&do=showConversation&topicID={$msg_topic_id}#msg{$msg_id}"); IPSText::getTextClass('email')->setPlainTextTemplate(IPSText::getTextClass('email')->getTemplate('personal_convo_new_convo', $toMember['language'])); IPSText::getTextClass('email')->buildPlainTextContent($buildMessage); IPSText::getTextClass('email')->subject = sprintf(IPSText::getTextClass('email')->subject, $this->registry->output->buildSEOUrl('showuser='******'member_id'], 'public', $fromMemberData['members_seo_name'], 'showuser'), $fromMemberData['members_display_name'], $this->registry->output->buildUrl("app=members&module=messaging§ion=view&do=showConversation&topicID={$msg_topic_id}#msg{$msg_id}", 'public')); $notifyLibrary->setMember($toMember); $notifyLibrary->setFrom($fromMemberData); $notifyLibrary->setNotificationKey('new_private_message'); $notifyLibrary->setNotificationUrl($this->registry->output->buildUrl("app=members&module=messaging§ion=view&do=showConversation&topicID={$msg_topic_id}#msg{$msg_id}", 'public')); $notifyLibrary->setNotificationText(IPSText::getTextClass('email')->getPlainTextContent()); $notifyLibrary->setNotificationTitle(IPSText::getTextClass('email')->subject); $notifyLibrary->setNotificationHtml(IPSText::getTextClass('email')->buildHtmlContent($buildMessage)); $notifyLibrary->setMetaData(array('meta_area' => 'pm', 'meta_id' => $msg_topic_id, 'meta_app' => 'members')); try { $notifyLibrary->sendNotification(); } catch (Exception $e) { } IPSMember::save($toMember['member_id'], array('core' => array('msg_count_total' => 'plus:1', 'msg_count_new' => 'plus:1', 'msg_count_reset' => 1))); } else { IPSMember::save($toMember['member_id'], array('core' => array('msg_count_total' => 'plus:1'))); } } } else { //----------------------------------------- // Is a draft //----------------------------------------- /* Create user map entry */ $this->DB->insert('message_topic_user_map', array('map_user_id' => $fromMemberData['member_id'], 'map_topic_id' => $msg_topic_id, 'map_folder_id' => 'drafts', 'map_user_active' => 1, 'map_has_unread' => 0, 'map_user_banned' => 0, 'map_read_time' => 0, 'map_left_time' => 0, 'map_ignore_notification' => 0, 'map_last_topic_reply' => IPS_UNIX_TIME_NOW)); if (!$options['topicID']) { //----------------------------------------- // Update profile //----------------------------------------- $this->rebuildFolderCount($fromMemberData['member_id'], array('drafts' => 'plus:1'), TRUE, array('core' => array('msg_count_total' => 'plus:1'))); } } return TRUE; }
/** * Get Topic Data * * @return array */ public function _getPosts() { /* Init */ $topicData = $this->registry->getClass('topics')->getTopicData(); $forumData = $this->forumClass->getForumById($topicData['forum_id']); $permissionData = $this->registry->getClass('topics')->getPermissionData(); $first = $this->registry->getClass('topics')->pageToSt($this->request['page']); /* Default - just see all visible posts */ $queued_query_bit = ' AND ' . $this->registry->class_forums->fetchPostHiddenQuery('visible', ''); /* Can we deal with hidden posts? */ if ($this->registry->class_forums->canQueuePosts($topicData['forum_id'])) { if ($permissionData['softDeleteSee']) { /* See queued and soft deleted */ $queued_query_bit = ' AND ' . $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden', 'sdeleted'), ''); } else { /* Otherwise, see queued and approved */ $queued_query_bit = ' AND ' . $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden'), ''); } /* Specifically requesting to see queued posts only */ if ($this->request['modfilter'] and $this->request['modfilter'] == 'invisible_posts') { $queued_query_bit = ' AND ' . $this->registry->class_forums->fetchPostHiddenQuery('hidden', ''); } } else { /* We cannot see hidden posts */ if ($permissionData['softDeleteSee']) { /* See queued and soft deleted */ $queued_query_bit = ' AND ' . $this->registry->class_forums->fetchPostHiddenQuery(array('approved', 'sdeleted'), ''); } } /* Did we specifically want to see soft deleted posts? */ if ($this->request['modfilter'] == 'deleted_posts' and $permissionData['softDeleteSee']) { $queued_query_bit = ' AND ' . $this->registry->class_forums->fetchPostHiddenQuery('sdeleted', ''); } /* Data Hook Location */ $dataHook = array('members' => array(), 'postJoins' => array()); IPSLib::doDataHooks($dataHook, 'topicViewQuery'); //----------------------------------------- // Joins //----------------------------------------- $_extraMember = is_array($dataHook['members']) && count($dataHook['members']) ? ',m.' . implode(',m.', $dataHook['members']) : ''; $_post_joins = array(array('select' => '', 'from' => array('posts' => 'p'), 'where' => 'p.pid=z.pid'), array('select' => 'm.member_id as mid,m.name,m.member_group_id,m.email,m.joined,m.posts, m.last_visit, m.last_activity,m.login_anonymous,m.title as member_title, m.warn_level, m.warn_lastwarn, m.members_display_name, m.members_seo_name, m.member_banned, m.has_gallery, m.has_blog, m.members_bitoptions,m.mgroup_others' . $_extraMember, 'from' => array('members' => 'm'), 'where' => 'm.member_id=p.author_id', 'type' => 'left'), array('select' => 'pp.*', 'from' => array('profile_portal' => 'pp'), 'where' => 'm.member_id=pp.pp_member_id', 'type' => 'left')); /* Warn system enabled? */ if ($this->settings['warn_on'] == 1) { $_post_joins[] = array('select' => 'w.wl_id', 'from' => array('members_warn_logs' => 'w'), 'where' => 'w.wl_content_app=\'forums\' and w.wl_content_id1=p.pid'); } /* Add data hook joins */ if (is_array($dataHook['postJoins']) && count($dataHook['postJoins'])) { $_post_joins = array_merge($_post_joins, $dataHook['postJoins']); } /* Add custom fields join? */ if ($this->settings['custom_profile_topic'] == 1) { $_post_joins[] = array('select' => 'pc.*', 'from' => array('pfields_content' => 'pc'), 'where' => 'pc.member_id=p.author_id', 'type' => 'left'); } /* Reputation system enabled? */ if ($this->settings['reputation_enabled']) { /* Add the join to figure out if the user has already rated the post */ $_post_joins[] = $this->registry->repCache->getUserHasRatedJoin('pid', 'p.pid', 'forums'); /* Add the join to figure out the total ratings for each post */ if ($this->settings['reputation_show_content']) { $_post_joins[] = $this->registry->repCache->getTotalRatingJoin('pid', 'p.pid', 'forums'); } } /* Cache? */ if (IPSContentCache::isEnabled()) { if (IPSContentCache::fetchSettingValue('post')) { $_post_joins[] = IPSContentCache::join('post', 'p.pid'); } if (IPSContentCache::fetchSettingValue('sig')) { $_post_joins[] = IPSContentCache::join('sig', 'm.member_id', 'ccb', 'left', 'ccb.cache_content as cache_content_sig, ccb.cache_updated as cache_updated_sig'); } } /* Ignored Users */ $ignored_users = array(); foreach ($this->member->ignored_users as $_i) { if ($_i['ignore_topics']) { $ignored_users[] = $_i['ignore_ignore_id']; } } //----------------------------------------- // Get posts // See http://community.invisionpower.com/resources/bugs.html/_/ip-board/big-topics-i-mean-big-topics-r36577 for an explanation why this a bit odd //----------------------------------------- $this->DB->build(array('select' => 'p.*', 'from' => array('( ****FROM**** )' => 'z'), 'add_join' => $_post_joins)); $query = $this->DB->fetchSqlString(); $this->DB->flushQuery(); $this->DB->build(array('select' => 'pid, post_date', 'from' => 'posts', 'where' => 'topic_id=' . $topicData['tid'] . $queued_query_bit, 'order' => $this->settings['post_order_column'] . ' ' . $this->settings['post_order_sort'], 'limit' => array($first, $this->settings['display_max_posts']))); $query = str_replace('****FROM****', $this->DB->fetchSqlString(), $query) . " ORDER BY z." . $this->settings['post_order_column'] . " " . $this->settings['post_order_sort']; $query = str_replace($this->settings['sql_tbl_prefix'] . '(', '(', $query); $this->DB->flushQuery(); $this->DB->allow_sub_select = TRUE; $oq = $this->DB->query($query); if (!$this->DB->getTotalRows()) { if ($first >= $this->settings['display_max_posts']) { //----------------------------------------- // AUTO FIX: Get the correct number of replies... //----------------------------------------- $this->DB->build(array('select' => 'COUNT(*) as pcount', 'from' => 'posts', 'where' => "topic_id=" . $topicData['tid'] . " and queued=0")); $newq = $this->DB->execute(); $pcount = $this->DB->fetch($newq); $pcount['pcount'] = $pcount['pcount'] > 0 ? $pcount['pcount'] - 1 : 0; //----------------------------------------- // Update the post table... //----------------------------------------- if ($pcount['pcount'] > 1) { $this->DB->update('topics', array('posts' => $pcount['pcount']), "tid=" . $topicData['tid']); } // This is now handled in app_class_forums::incorrectPageCallback to redirect to correct post */ //$this->registry->output->silentRedirect($this->settings['base_url']."showtopic={$topicData['tid']}&view=getlastpost"); } } //----------------------------------------- // Render the page top //----------------------------------------- $topicData['go_new'] = isset($topicData['go_new']) ? $topicData['go_new'] : ''; //----------------------------------------- // Format and print out the topic list //----------------------------------------- $modAll = ($this->memberData['g_is_supmod'] or isset($this->memberData['forumsModeratorData'][$forumData['id']]) and ($this->memberData['forumsModeratorData'][$forumData['id']]['delete_post'] or $this->memberData['forumsModeratorData'][$forumData['id']]['split_move'])); $this->registry->getClass('topics')->setTopicData('adCodeSet', false); $this->registry->getClass('topics')->setTopicData('ignoredUsers', $ignored_users); $posts = array(); $this->DB->allow_sub_select = TRUE; while ($row = $this->DB->fetch($oq)) { /* Should we display the moderate checkbox for this post? */ $row['moddable'] = FALSE; if ($modAll or isset($this->memberData['forumsModeratorData'][$forumData['id']]) and ($row['approved'] == 0 and $this->memberData['forumsModeratorData'][$forumData['id']]['post_q'] or $row['queued'] == 2 and $this->memberData['forumsModeratorData'][$forumData['id']]['bw_mod_un_soft_delete'] or $row['queued'] == 0 and $this->memberData['forumsModeratorData'][$forumData['id']]['bw_mod_soft_delete'])) { $row['moddable'] = TRUE; } /* Add to array */ $row['member_id'] = $row['mid']; $posts[$row['pid']] = $row; } /* Return */ return $posts; }
/** * Adds a friend to the account that is logged in or specified * * @param integer $friend_id The friend being added to the account * @param integer $from_id The requesting member, defaults to current member * @param boolean $forceApproval Automatically approve, regardless of setting * @param boolean $sendNotification If false, no notification will be sent to the member being added * @return string Error Key or blank for success */ public function addFriend($friend_id, $from_id = 0, $forceApproval = false, $sendNotification = true) { /* INIT */ $friend_id = intval($friend_id); $from_id = $from_id ? intval($from_id) : $this->memberData['member_id']; $friend = array(); $member = array(); $friends_approved = 1; $message = ''; $subject = ''; $to = array(); $from = array(); $return_msg = ''; /* Can't add yourself */ if ($from_id == $friend_id) { return 'error'; } /* Load our friends account */ $friend = IPSMember::load($friend_id); /* Load our account */ $member = IPSMember::load($from_id); /* This group not allowed to add friends */ if (!$member['g_can_add_friends']) { return 'error'; } /* Make sure we found ourselves and our friend */ if (!$friend['member_id'] or !$member['member_id']) { return 'error'; } /* Are we already friends? */ $friend_check = $this->DB->buildAndFetch(array('select' => 'friends_id', 'from' => 'profile_friends', 'where' => "friends_member_id={$from_id} AND friends_friend_id={$friend_id}")); if ($friend_check['friends_id']) { return 'pp_friend_already'; } /* Check flood table */ if ($this->_canAddFriend($from_id, $friend['member_id']) !== TRUE) { return 'pp_friend_timeflood'; } /* Do we approve our friends first? */ if (!$forceApproval and $friend['pp_setting_moderate_friends']) { $friends_approved = 0; $this->pendingApproval = true; } $_profileFriendsData = array('friends_member_id' => $member['member_id'], 'friends_friend_id' => $friend['member_id'], 'friends_approved' => $friends_approved, 'friends_added' => time()); /* Data Hook Location */ IPSLib::doDataHooks($_profileFriendsData, 'profileFriendsNew'); /* Insert the friend */ $this->DB->insert('profile_friends', $_profileFriendsData); /* Do we need to send notifications? */ if (!$friends_approved) { //----------------------------------------- // Notifications library //----------------------------------------- if ($sendNotification) { $classToLoad = IPSLib::loadLibrary(IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications'); $notifyLibrary = new $classToLoad($this->registry); IPSText::getTextClass('email')->getTemplate("new_friend_request", $friend['language']); IPSText::getTextClass('email')->buildMessage(array('MEMBERS_DISPLAY_NAME' => $friend['members_display_name'], 'FRIEND_NAME' => $member['members_display_name'], 'LINK' => "{$this->settings['board_url']}/index.{$this->settings['php_ext']}?app=members&section=friends&module=profile&do=list&tab=pending")); IPSText::getTextClass('email')->subject = sprintf(IPSText::getTextClass('email')->subject, $this->registry->output->buildSEOUrl('showuser='******'member_id'], 'public', $member['members_seo_name'], 'showuser'), $member['members_display_name'], "{$this->settings['board_url']}/index.{$this->settings['php_ext']}?app=members&section=friends&module=profile&do=list&tab=pending"); $notifyLibrary->setMember($friend); $notifyLibrary->setFrom($member); $notifyLibrary->setNotificationKey('friend_request'); $notifyLibrary->setNotificationUrl("{$this->settings['board_url']}/index.{$this->settings['php_ext']}?app=members&section=friends&module=profile&do=list&tab=pending"); $notifyLibrary->setNotificationText(IPSText::getTextClass('email')->message); $notifyLibrary->setNotificationTitle(IPSText::getTextClass('email')->subject); try { $notifyLibrary->sendNotification(); } catch (Exception $e) { } } $return_msg = 'pp_friend_added_mod'; } else { /* Don't notify yourself */ if ($sendNotification and $friend['member_id'] != $this->memberData['member_id']) { //----------------------------------------- // Notifications library //----------------------------------------- $classToLoad = IPSLib::loadLibrary(IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications'); $notifyLibrary = new $classToLoad($this->registry); IPSText::getTextClass('email')->getTemplate("new_friend_added", $friend['language']); IPSText::getTextClass('email')->buildMessage(array('MEMBERS_DISPLAY_NAME' => $friend['members_display_name'], 'FRIEND_NAME' => $member['members_display_name'], 'LINK' => "{$this->settings['board_url']}/index.{$this->settings['php_ext']}?app=members&section=friends&module=profile&do=list")); IPSText::getTextClass('email')->subject = sprintf(IPSText::getTextClass('email')->subject, $this->registry->output->buildSEOUrl('showuser='******'member_id'], 'public', $member['members_seo_name'], 'showuser'), $member['members_display_name']); $notifyLibrary->setMember($friend); $notifyLibrary->setFrom($member); $notifyLibrary->setNotificationKey('friend_request'); $notifyLibrary->setNotificationUrl($this->registry->output->buildSEOUrl('showuser='******'member_id'], 'public', $member['members_seo_name'], 'showuser')); $notifyLibrary->setNotificationText(IPSText::getTextClass('email')->message); $notifyLibrary->setNotificationTitle(IPSText::getTextClass('email')->subject); try { $notifyLibrary->sendNotification(); } catch (Exception $e) { } } $return_msg = 'pp_friend_added'; } /* Reache */ $this->recacheFriends($member); $this->recacheFriends($friend); return ''; }
/** * Toggles visibility * * @param string on/off * @param array Array of comment IDs to be deleted * @param int Parent ID * @return void */ public function postVisibility($toggle, $commentIds, $parentId) { $this->_rebuildCommentCount($parentId); $_dataHook = array('toggle' => $toggle, 'commentIds' => $commentIds, 'parentId' => $parentId); /* Data Hook Location */ IPSLib::doDataHooks($_dataHook, 'calendarCommentToggleVisibility'); }
/** * Saves the add/edit calendar event form * * @param string $type Either add or edit * @return @e void */ public function calendarEventSave($type = 'add') { //----------------------------------------- // Check permissions //----------------------------------------- if ($this->request['auth_key'] != $this->member->form_hash) { $this->registry->output->showError('no_permission', 10410, null, null, 403); } if ($this->request['preview']) { return $this->calendarEventForm($type); } //----------------------------------------- // Init //----------------------------------------- $event_id = intval($this->request['event_id']); $calendar_id = intval($this->request['event_calendar_id']); $_calendar = $this->functions->getCalendar($calendar_id); $event_title = IPSText::getTextClass('bbcode')->stripBadWords(trim($this->request['event_title'])); $start_date = ''; $end_date = ''; $recurring = 0; //----------------------------------------- // Verify start date/time //----------------------------------------- switch ($this->settings['cal_date_format']) { case 'american': default: $_startBits = explode('/', $this->request['start_date']); if ($this->request['set_enddate']) { $_endBits = $this->request['end_date'] ? explode('/', $this->request['end_date']) : array(); } break; case 'danish': $_inputStart = explode('/', $this->request['start_date']); $_startBits = array(0 => $_inputStart[1], 1 => $_inputStart[2], 2 => $_inputStart[0]); if ($this->request['set_enddate']) { $_inputEnd = $this->request['end_date'] ? explode('/', $this->request['end_date']) : array(); $_endBits = array(0 => $_inputEnd[1], 1 => $_inputEnd[2], 2 => $_inputEnd[0]); } break; case 'italian': $_inputStart = explode('/', $this->request['start_date']); $_startBits = array(0 => $_inputStart[1], 1 => $_inputStart[0], 2 => $_inputStart[2]); if ($this->request['set_enddate']) { $_inputEnd = $this->request['end_date'] ? explode('/', $this->request['end_date']) : array(); $_endBits = array(0 => $_inputEnd[1], 1 => $_inputEnd[0], 2 => $_inputEnd[2]); } break; case 'db': $_inputStart = explode('-', $this->request['start_date']); $_startBits = array(0 => $_inputStart[1], 1 => $_inputStart[2], 2 => $_inputStart[0]); if ($this->request['set_enddate']) { $_inputEnd = $this->request['end_date'] ? explode('-', $this->request['end_date']) : array(); $_endBits = array(0 => $_inputEnd[1], 1 => $_inputEnd[2], 2 => $_inputEnd[0]); } break; } if (!$this->request['start_date'] or count($_startBits) != 3) { $this->registry->output->showError('calendar_invalid_date', 10427.0); } else { if (!@checkdate($_startBits[0], $_startBits[1], $_startBits[2])) { $this->registry->output->showError('calendar_invalid_date', 10427.1); } } if ($this->request['all_day']) { $start_date = gmmktime(0, 0, 0, $_startBits[0], $_startBits[1], $_startBits[2]); } else { $_time = explode(':', $this->request['start_time']); if ($this->settings['cal_time_format'] == 'standard') { if (count($_time) != 2 or $_time[0] > 12 or $_time[1] > 59) { $this->registry->output->showError('calendar_invalid_time', 10427.2); } if ($this->request['start_time_ampm'] == 'PM' and $_time[0] < 12) { $_time[0] += 12; } else { if ($this->request['start_time_ampm'] == 'AM' and $_time[0] == 12) { $_time[0] = 0; } } } else { if (count($_time) != 2 or $_time[0] > 23 or $_time[1] > 59) { $this->registry->output->showError('calendar_invalid_time', 10427.2); } } $start_date = gmmktime($_time[0], $_time[1], 0, $_startBits[0], $_startBits[1], $_startBits[2]); } //----------------------------------------- // Verify end date/time //----------------------------------------- if ($this->request['set_enddate']) { if (count($_endBits) != 3) { $this->registry->output->showError('calendar_invalid_date', 10427.3); } else { if (!@checkdate($_endBits[0], $_endBits[1], $_endBits[2])) { $this->registry->output->showError('calendar_invalid_date', 10427.4); } } if ($this->request['all_day']) { $end_date = gmmktime(0, 0, 0, $_endBits[0], $_endBits[1], $_endBits[2]); } else { $_time = explode(':', $this->request['end_time']); if ($this->settings['cal_time_format'] == 'standard') { if (count($_time) != 2 or $_time[0] > 12 or $_time[1] > 59) { $this->registry->output->showError('calendar_invalid_date', 10427.5); } if ($this->request['end_time_ampm'] == 'PM') { $_time[0] += 12; } } else { if (count($_time) != 2 or $_time[0] > 23 or $_time[1] > 59) { $this->registry->output->showError('calendar_invalid_date', 10427.5); } } $end_date = gmmktime($_time[0], $_time[1], 0, $_endBits[0], $_endBits[1], $_endBits[2]); } } if ($end_date and $end_date < $start_date) { $this->registry->output->showError('calendar_range_wrong', 10421); } else { if ($this->request['end_date'] and $this->request['set_enddate'] and !$end_date) { $this->registry->output->showError('calendar_range_wrong', 10421.1); } } //----------------------------------------- // Set recurring flag //----------------------------------------- if ($this->request['set_recurfields']) { if (!$end_date) { $this->registry->output->showError('recurring_requires_enddate', 10427.6); } $recurring = intval($this->request['recur_unit']); } //----------------------------------------- // Adjust to GMT //----------------------------------------- if ($this->request['event_timezone'] and !$this->request['all_day']) { $start_date = $start_date - $this->request['event_timezone'] * 3600; if ($end_date) { $end_date = $end_date - $this->request['event_timezone'] * 3600; } } $start_date = gmstrftime("%Y-%m-%d %H:%M:00", $start_date); $end_date = $end_date ? gmstrftime("%Y-%m-%d %H:%M:00", $end_date) : 0; //----------------------------------------- // Check posted content for errors //----------------------------------------- if (strlen(trim(IPSText::removeControlCharacters(IPSText::br2nl($_POST['Post'])))) < 1) { $this->registry->output->showError('calendar_post_too_short', 10417, null, null, 403); } $this->settings['max_post_length'] = $this->settings['max_post_length'] ? $this->settings['max_post_length'] : 2140000; if (IPSText::mbstrlen($_POST['Post']) > $this->settings['max_post_length'] * 1024) { $this->registry->output->showError('calendar_post_too_long', 10418, null, null, 403); } if (!$event_title or IPSText::mbstrlen($event_title) < 2) { $this->registry->output->showError('calendar_no_title', 10419, null, null, 403); } if (IPSText::mbstrlen($event_title) > 200) { $this->registry->output->showError('calendar_title_too_long', 10420, null, null, 403); } //----------------------------------------- // Adding or editing? //----------------------------------------- if ($type == 'edit') { //----------------------------------------- // Get event //----------------------------------------- if (!$event_id) { $this->registry->output->showError('calendar_event_not_found', 10414, null, null, 404); } $event = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'cal_events', 'where' => 'event_id=' . $event_id)); if (!$event['event_id']) { $this->registry->output->showError('calendar_event_not_found', 10415, null, null, 404); } //----------------------------------------- // Do we have permission to edit? //----------------------------------------- if (!$this->memberData['g_is_supmod'] and $this->memberData['member_id'] != $event['event_member_id']) { $this->registry->output->showError('calendar_no_edit_perm', 10416, null, null, 403); } } //----------------------------------------- // Set event view permissions //----------------------------------------- if ($this->memberData['g_access_cp']) { if (is_array($this->request['e_groups'])) { foreach ($this->cache->getCache('group_cache') as $group) { if ($group['g_access_cp']) { $this->request['e_groups'][] = $group['g_id']; } } $read_perms = implode(",", $this->request['e_groups']); } } $read_perms = $read_perms ? $read_perms : '*'; //----------------------------------------- // Get editor and format post //----------------------------------------- $classToLoad = IPSLib::loadLibrary(IPS_ROOT_PATH . 'sources/classes/editor/composite.php', 'classes_editor_composite'); $editor = new $classToLoad(); $event_content = $editor->process($_POST['Post']); IPSText::getTextClass('bbcode')->parse_html = 0; IPSText::getTextClass('bbcode')->parse_smilies = intval($this->request['enableemo']); IPSText::getTextClass('bbcode')->parse_bbcode = 1; IPSText::getTextClass('bbcode')->parsing_section = 'calendar'; $event_content = IPSText::getTextClass('bbcode')->preDbParse($event_content); //----------------------------------------- // Event approved? //----------------------------------------- if ($this->request['e_type'] == 'private') { $event_approved = 1; } else { $event_approved = $this->registry->permissions->check('nomod', $_calendar) ? 1 : ($_calendar['cal_moderate'] ? 0 : 1); } //----------------------------------------- // Store the event //----------------------------------------- if ($type == 'add') { //----------------------------------------- // Format array for storage //----------------------------------------- $_eventData = array('event_calendar_id' => $calendar_id, 'event_member_id' => $this->memberData['member_id'], 'event_content' => $event_content, 'event_title' => $event_title, 'event_title_seo' => IPSText::makeSeoTitle($event_title), 'event_smilies' => intval($this->request['enableemo']), 'event_comments' => 0, 'event_perms' => $read_perms, 'event_private' => $this->request['e_type'] == 'private' ? 1 : 0, 'event_approved' => $event_approved, 'event_saved' => time(), 'event_lastupdated' => time(), 'event_recurring' => $recurring, 'event_start_date' => $start_date, 'event_end_date' => $end_date, 'event_post_key' => $this->request['post_key'], 'event_rsvp' => $this->registry->permissions->check('askrsvp', $_calendar) ? intval($this->request['event_rsvp']) : 0, 'event_sequence' => 0, 'event_all_day' => intval($this->request['all_day'])); //----------------------------------------- // Data hooks //----------------------------------------- IPSLib::doDataHooks($_eventData, 'calendarAddEvent'); //----------------------------------------- // Insert //----------------------------------------- $this->DB->insert('cal_events', $_eventData); $event_id = $this->DB->getInsertId(); //----------------------------------------- // Set language strings //----------------------------------------- $_langString = $event_approved ? $this->lang->words['new_event_redirect'] : $this->lang->words['new_event_mod']; } else { //----------------------------------------- // Format array for storage //----------------------------------------- $_eventData = array('event_calendar_id' => $calendar_id, 'event_content' => $event_content, 'event_title' => $event_title, 'event_title_seo' => IPSText::makeSeoTitle($event_title), 'event_smilies' => intval($this->request['enableemo']), 'event_perms' => $read_perms, 'event_private' => $this->request['e_type'] == 'private' ? 1 : 0, 'event_approved' => $event_approved, 'event_lastupdated' => time(), 'event_recurring' => $recurring, 'event_start_date' => $start_date, 'event_end_date' => $end_date, 'event_post_key' => $this->request['post_key'], 'event_rsvp' => $this->registry->permissions->check('askrsvp', $_calendar) ? intval($this->request['event_rsvp']) : $event['event_rsvp'], 'event_sequence' => intval($event['event_rsvp']) + 1, 'event_all_day' => intval($this->request['all_day'])); //----------------------------------------- // Data hooks //----------------------------------------- IPSLib::doDataHooks($_eventData, 'calendarEditEvent'); //----------------------------------------- // Update database //----------------------------------------- $this->DB->update('cal_events', $_eventData, 'event_id=' . $event_id); //----------------------------------------- // Set language strings //----------------------------------------- $_langString = $event_approved ? $this->lang->words['edit_event_redirect'] : $this->lang->words['new_event_mod']; } //----------------------------------------- // Upload attachments //----------------------------------------- if ($this->memberData['g_attach_max'] != -1) { $classToLoad = IPSLib::loadLibrary(IPSLib::getAppDir('core') . '/sources/classes/attach/class_attach.php', 'class_attach'); $class_attach = new $classToLoad($this->registry); $class_attach->type = 'event'; $class_attach->attach_post_key = $_eventData['event_post_key']; $class_attach->attach_rel_id = $event_id; $class_attach->init(); $class_attach->processMultipleUploads(); $class_attach->postProcessUpload(array()); } //----------------------------------------- // Send notifications //----------------------------------------- if ($event_approved) { require_once IPS_ROOT_PATH . 'sources/classes/like/composite.php'; /*noLibHook*/ $_like = classes_like::bootstrap('calendar', $type == 'edit' ? 'events' : 'calendars'); $_url = $this->registry->output->buildSEOUrl('app=calendar&module=calendar&section=view&do=showevent&event_id=' . $event_id, 'public', $_eventData['event_title_seo'], 'cal_event'); $_like->sendNotifications($type == 'edit' ? $event_id : $_eventData['event_calendar_id'], array('immediate', 'offline'), array('notification_key' => $type == 'edit' ? 'updated_event' : 'new_event', 'notification_url' => $_url, 'email_template' => $type . '_event_follow', 'email_subject' => sprintf($this->lang->words[$type . '_event_follow_subject'], $_url, $_eventData['event_title']), 'build_message_array' => array('NAME' => '-member:members_display_name-', 'AUTHOR' => $this->memberData['members_display_name'], 'TITLE' => $_eventData['event_title'], 'URL' => $_url))); } //----------------------------------------- // Rebuild cache //----------------------------------------- $this->cache->rebuildCache('calendar_events', 'calendar'); //----------------------------------------- // Redirect //----------------------------------------- if ($event_approved) { $this->registry->output->redirectScreen($_langString, $this->settings['base_url'] . "app=calendar&module=calendar&section=view&do=showevent&event_id=" . $event_id, $_eventData['event_title_seo'], 'cal_event'); } else { $this->registry->output->redirectScreen($_langString, $this->settings['base_url'] . "app=calendar&module=calendar&section=view&cal_id=" . $calendar_id, $this->caches['calendars'][$calendar_id]['cal_title_seo'], 'cal_calendar'); } }