/** * Render options that the user has for this category. */ function getOptions($Category) { if (!Gdn::session()->isValid()) { return; } $Sender = Gdn::controller(); $Result = ''; $Options = ''; $CategoryID = val('CategoryID', $Category); $Result = '<div class="Options">'; $TKey = urlencode(Gdn::session()->TransientKey()); // Mark category read. $Options .= '<li rel="MarkRead">' . anchor(t('Mark Read'), "/category/markread?categoryid={$CategoryID}&tkey={$TKey}") . '</li>'; // Follow/Unfollow category. if (!val('Following', $Category)) { $Options .= '<li rel="Hide">' . anchor(t('Unhide'), "/category/follow?categoryid={$CategoryID}&value=1&tkey={$TKey}") . '</li>'; } else { $Options .= '<li rel="Hide">' . anchor(t('Hide'), "/category/follow?categoryid={$CategoryID}&value=0&tkey={$TKey}") . '</li>'; } // Allow plugins to add options $Sender->EventArguments['Options'] =& $Options; $Sender->fireEvent('CategoryOptions'); if ($Options != '') { $Result .= '<span class="ToggleFlyout OptionsMenu">'; $Result .= '<span class="OptionsTitle">' . t('Options') . '</span>'; $Result .= '<span class="SpFlyoutHandle"></span>'; $Result .= '<ul class="Flyout MenuItems">' . $Options . '</ul>'; $Result .= '</span>'; $Result .= '</div>'; return $Result; } }
/** * Render. * * @return string */ public function toString() { if (!Gdn::session()->isValid()) { return parent::ToString(); } return ''; }
/** * A placeholder for future menu items. * * @param array $Params The parameters passed into the function. * @param Smarty $Smarty The smarty object rendering the template. * @return string */ function smarty_function_custom_menu($Params, &$Smarty) { $Controller = $Smarty->Controller; if (is_object($Menu = val('Menu', $Controller))) { $Format = val('format', $Params, wrap('<a href="%url" class="%class">%text</a>', val('wrap', $Params, 'li'))); $Result = ''; foreach ($Menu->Items as $Group) { foreach ($Group as $Item) { // Make sure the item is a custom item. if (valr('Attributes.Standard', $Item)) { continue; } // Make sure the user has permission for the item. if ($Permission = val('Permission', $Item)) { if (!Gdn::session()->checkPermission($Permission)) { continue; } } if (($Url = val('Url', $Item)) && ($Text = val('Text', $Item))) { $Attributes = val('Attributes', $Item); $Result .= Gdn_Theme::link($Url, $Text, $Format, $Attributes) . "\r\n"; } } } return $Result; } return ''; }
/** * Do some validations before discussion is saved. * * @param object $sender DiscussionModel. * @param array $args EventArguments. * @return void. * @package TwitterBot * @since 0.1 */ public function discussionModel_beforeSaveDiscussion_handler($sender, $args) { // If "Publish on Twitter" is unchecked, no sanity checks must be done if (!$args['FormPostValues']['TwitterBot']) { return; } // Check if plugin is configured $consumerKey = Gdn::config('TwitterBot.ConsumerKey'); $consumerSecret = Gdn::config('TwitterBot.ConsumerSecret'); $oAuthAccessToken = Gdn::config('TwitterBot.OAuthAccessToken'); $oAuthAccessTokenSecret = Gdn::config('TwitterBot.OAuthAccessTokenSecret'); if (!$consumerKey || !$consumerSecret || !$oAuthAccessToken || !$oAuthAccessTokenSecret) { return; } // Check for role permissions $roleIds = array_keys(Gdn::userModel()->getRoles(Gdn::session()->UserID)); if (array_intersect($roles, Gdn::config('TwitterBot.RoleIDs'))) { // Don't give feedback since this is only true on error or if // user has spoofed post data. Desired result is that discussion is // posted to forum without issues but not on Twitter. return; } // Check for allowed category $categoryID = $args['FormPostValues']['CategoryID']; if (!in_array($categoryID, Gdn::config('TwitterBot.CategoryIDs'))) { $sender->Validation->addValidationResult('CategoryID', 'Discussions in this category will not be published on Twitter. Please uncheck "Publish on Twitter" or choose a valid category.'); } // Check for restriction to announcements if (Gdn::config('TwitterBot.AnnouncementsOnly') && !$args['FormPostValues']['Announce']) { $sender->Validation->addValidationResult('Publish on Twitter', 'Only Announcements will be published on Twitter. Either make this an Announcement or uncheck the "Publich on Twitter" checkbox.'); } }
/** * * * @param array $Params * @param object $Smarty * @return string */ function smarty_function_signin_link($Params, &$Smarty) { if (!Gdn::session()->isValid()) { $Wrap = val('wrap', $Params, 'li'); return Gdn_Theme::link('signinout', val('text', $Params, ''), val('format', $Params, wrap('<a href="%url" rel="nofollow" class="%class">%text</a>', $Wrap)), $Params); } }
public function toString() { $HasPermission = Gdn::session()->checkPermission('Vanilla.Discussions.Add', true, 'Category', 'any'); if ($HasPermission) { echo anchor(t('Ask a Question'), '/post/discussion?Type=Question', 'Button BigButton NewQuestion'); } }
/** * Grabs all new notifications and adds them to the sender's inform queue. * * This method gets called by dashboard's hooks file to display new * notifications on every pageload. * * @since 2.0.18 * @access public * * @param Gdn_Controller $Sender The object calling this method. */ public static function informNotifications($Sender) { $Session = Gdn::session(); if (!$Session->isValid()) { return; } $ActivityModel = new ActivityModel(); // Get five pending notifications. $Where = array('NotifyUserID' => Gdn::session()->UserID, 'Notified' => ActivityModel::SENT_PENDING); // If we're in the middle of a visit only get very recent notifications. $Where['DateUpdated >'] = Gdn_Format::toDateTime(strtotime('-5 minutes')); $Activities = $ActivityModel->getWhere($Where, 0, 5)->resultArray(); $ActivityIDs = array_column($Activities, 'ActivityID'); $ActivityModel->setNotified($ActivityIDs); $Sender->EventArguments['Activities'] =& $Activities; $Sender->fireEvent('InformNotifications'); foreach ($Activities as $Activity) { if ($Activity['Photo']) { $UserPhoto = anchor(img($Activity['Photo'], array('class' => 'ProfilePhotoMedium')), $Activity['Url'], 'Icon'); } else { $UserPhoto = ''; } $Excerpt = Gdn_Format::plainText($Activity['Story']); $ActivityClass = ' Activity-' . $Activity['ActivityType']; $Sender->informMessage($UserPhoto . Wrap($Activity['Headline'], 'div', array('class' => 'Title')) . Wrap($Excerpt, 'div', array('class' => 'Excerpt')), 'Dismissable AutoDismiss' . $ActivityClass . ($UserPhoto == '' ? '' : ' HasIcon')); } }
/** * Delete a single draft. * * Redirects user back to Index unless DeliveryType is set. * * @since 2.0.0 * @access public * * @param int $DraftID Unique ID of draft to be deleted. * @param string $TransientKey Single-use hash to prove intent. */ public function delete($DraftID = '', $TransientKey = '') { $Form = Gdn::Factory('Form'); $Session = Gdn::session(); if (is_numeric($DraftID) && $DraftID > 0 && $Session->UserID > 0 && $Session->validateTransientKey($TransientKey)) { // Delete the draft $Draft = $this->DraftModel->getID($DraftID); if ($Draft && !$this->DraftModel->delete($DraftID)) { $Form->addError('Failed to delete discussion'); } } else { // Log an error $Form->addError('ErrPermission'); } // Redirect if ($this->_DeliveryType === DELIVERY_TYPE_ALL) { $Target = GetIncomingValue('Target', '/drafts'); redirect($Target); } // Return any errors if ($Form->errorCount() > 0) { $this->setJson('ErrorMessage', $Form->errors()); } // Render default view $this->render(); }
/** * Token-based, per-request authentication * * This method takes the entire request string and turns the query into an * array of data. It then uses all the data to generate a signature the same * way it got generated on the client. If the server signature and client * token match, the client is considered legimate and the request is served. * * Based on initial work by Diego Zanella * @link http://careers.stackoverflow.com/diegozanella * * @since 0.1.0 * @access public * @throws Exception * @return void * @static */ public static function authenticateRequest() { $username = getIncomingValue("username"); $email = getIncomingValue("email"); if (!$username && !$email) { throw new Exception(t("API.Error.User.Missing"), 401); } if (!($userID = static::getUserID($username, $email))) { throw new Exception(t("API.Error.User.Invalid"), 401); } if (!($timestamp = getIncomingValue("timestamp"))) { throw new Exception(t("API.Error.Timestamp.Missing"), 401); } // Make sure that request is still valid if (abs($timestamp - time()) > c("API.Expiration")) { throw new Exception(t("API.Error.Timestamp.Invalid"), 401); } if (!($token = getIncomingValue("token"))) { throw new Exception(t("API.Error.Token.Missing"), 401); } $parsedUrl = parse_url(Gdn::request()->pathAndQuery()); // Turn the request query data into an array to be used in the token // generation parse_str(val("query", $parsedUrl, []), $data); // Unset the values we don't want to include in the token generation unset($data["token"], $data["DeliveryType"], $data["DeliveryMethod"]); if ($token != ($signature = static::generateSignature($data))) { throw new Exception(t("API.Error.Token.Invalid"), 401); } // Now that the client has been thoroughly verified, start a session for // the duration of the request using the User ID specified earlier if ($token == $signature) { Gdn::session()->start(intval($userID), false); } }
/** * Add Debugger info to every page. * * @param $Sender */ public function base_afterBody_handler($Sender) { $Session = Gdn::session(); if (!Debug() && !$Session->checkPermission('Plugins.Debugger.View')) { return; } require $Sender->fetchViewLocation('Debug', '', 'plugins/Debugger'); }
/** * Register API endpoints * * @since 0.1.0 * @access public * @param array $data * @return void * @static */ public static function register($data) { static::get("/", ["controller" => "Messages", "method" => "all", "authenticate" => true, "arguments" => ["Page" => val("Page", $data)]]); static::get("/[i:ConversationID]", ["controller" => "Messages", "authenticate" => true, "arguments" => ["Offset" => val("Offset", $data), "Limit" => val("Limit", $data)]]); static::post("/", ["controller" => "Messages", "method" => "add"]); static::post("/[i:ConversationID]/messages", ["controller" => "Messages", "method" => "addMessage"]); static::delete("/[i:ConversationID]", ["controller" => "Messages", "method" => "clear", "arguments" => ["TransientKey" => Gdn::session()->transientKey()]]); }
/** * Register API endpoints * * @since 0.1.0 * @access public * @param array $data * @return void * @static */ public static function register($data) { static::get("/", ["controller" => "Activity"]); static::get("/[i:ActivityID]", ["controller" => "Activity", "method" => "item"]); static::post("/", ["controller" => "Activity", "method" => "post", "arguments" => ["Notify" => val("Notify", $data)]]); static::post("/[i:ActivityID]/comments", ["controller" => "Activity", "method" => "comment"]); static::delete("/[i:ActivityID]", ["controller" => "Activity", "method" => "delete", "arguments" => ["TransientKey" => Gdn::session()->transientKey()]]); static::delete("/comments/[i:ID]", ["controller" => "Activity", "method" => "deleteComment", "arguments" => ["TK" => Gdn::session()->transientKey()]]); }
public function getData($Limit = 20, $DiscussionID = '') { $Session = Gdn::session(); if ($Session->isValid()) { $DraftModel = new DraftModel(); $this->Data = $DraftModel->get($Session->UserID, 0, $Limit, $DiscussionID); } $this->Form = $this->_Sender->Form; }
/** * Add Debugger info to dashboard after content asset. * * @param $sender * @param $args */ public function base_afterRenderAsset_handler($sender, $args) { if (val('AssetName', $args) == 'Content' && $sender->MasterView == 'admin') { $session = Gdn::session(); if (!Debug() || !$session->checkPermission('Plugins.Debugger.View')) { return; } require $sender->fetchViewLocation('Debug', '', 'plugins/Debugger'); } }
public function loadData() { $UserID = Gdn::controller()->data('Profile.UserID', Gdn::session()->UserID); $this->User = Gdn::userModel()->getID($UserID); $this->Roles = Gdn::userModel()->GetRoles($UserID)->resultArray(); // Hide personal info roles if (!checkPermission('Garden.PersonalInfo.View')) { $this->Roles = array_filter($this->Roles, 'RoleModel::FilterPersonalInfo'); } }
public function markRead($CategoryID, $TKey) { if (Gdn::session()->validateTransientKey($TKey)) { $this->CategoryModel->SaveUserTree($CategoryID, array('DateMarkedRead' => Gdn_Format::toDateTime())); } if ($this->deliveryType() == DELIVERY_TYPE_ALL) { redirect('/categories'); } $this->render(); }
/** * Register API endpoints * * @since 0.1.0 * @access public * @param array $data * @return void * @static */ public static function register($data) { static::get("/", ["controller" => "Categories", "method" => "all"]); static::get("/[i:CategoryIdentifier]", ["controller" => "Categories"]); static::post("/", ["application" => "Vanilla", "controller" => "Settings", "method" => "addCategory"]); static::post("/[i:CategoryID]/follow", ["controller" => "Category", "method" => "follow", "authenticate" => true, "arguments" => ["Value" => 1, "TKey" => Gdn::session()->transientKey()]]); static::post("/[i:CategoryID]/unfollow", ["controller" => "Category", "method" => "follow", "authenticate" => true, "arguments" => ["Value" => 0, "TKey" => Gdn::session()->transientKey()]]); static::put("/[i:CategoryID]", ["application" => "Vanilla", "controller" => "Settings", "method" => "editCategory"]); static::delete("/[i:CategoryID]", ["application" => "Vanilla", "controller" => "Settings", "method" => "deleteCategory"]); }
/** * * * @param $Sender */ public function settingsController_privateCommunity_create($Sender) { $Session = Gdn::session(); $Switch = val(0, $Sender->RequestArgs); $TransientKey = val(1, $Sender->RequestArgs); if (in_array($Switch, array('on', 'off')) && $Session->validateTransientKey($TransientKey) && $Session->checkPermission('Garden.Settings.Manage')) { saveToConfig('Garden.PrivateCommunity', $Switch == 'on' ? false : true); } redirect('dashboard/role'); }
public function toString() { if (!Gdn::session()->isValid()) { return ''; } if (!$this->data('Conversations')) { $this->getData(); } return parent::toString(); }
/** * PocketsPlugin constructor. */ public function __construct() { parent::__construct(); // Switch our HTML wrapper when we're in a table view. if (c('Vanilla.Discussions.Layout') == 'table') { // Admin checks add a column. $useAdminChecks = c('Vanilla.AdminCheckboxes.Use') && Gdn::session()->checkPermission('Garden.Moderation.Manage'); $colspan = c('Plugins.Pockets.Colspan', $useAdminChecks ? 6 : 5); $this->Locations['BetweenDiscussions']['Wrap'] = ['<tr><td colspan="' . $colspan . '">', '</td></tr>']; } }
/** * Stash a value in the user's session, or unstash it if no value was provided to stash. * * Looks for Name and Value POST/GET variables to pass along to Gdn_Session. */ public function stash() { $this->deliveryType(DELIVERY_TYPE_BOOL); $this->deliveryMethod(DELIVERY_METHOD_JSON); $Name = TrueStripSlashes(val('Name', $_POST, '')); $Value = TrueStripSlashes(val('Value', $_POST, '')); $Response = Gdn::session()->Stash($Name, $Value); if ($Name != '' && $Value == '') { $this->setJson('Unstash', $Response); } $this->render(); }
/** * Show the contributor agreement form & workflow for signing. */ public function index() { if (!Gdn::session()->isValid()) { $this->View = 'signin'; } else { if ($this->Form->authenticatedPostBack() && $this->Form->getFormValue('Agree', '') == '1') { Gdn::sql()->update('User')->set('DateContributorAgreement', Gdn_Format::toDateTime(), true, false)->where('UserID', Gdn::session()->UserID)->put(); $this->View = 'done'; } } $this->render(); }
/** * Adds a "My Forums" menu option to the dashboard area. */ public function settingsController_render_before($Sender) { // Have they visited their dashboard? if (strtolower($Sender->RequestMethod) != 'index') { $this->saveStep('Plugins.GettingStarted.Dashboard'); } // Save the action if editing registration settings if (strcasecmp($Sender->RequestMethod, 'registration') == 0 && $Sender->Form->authenticatedPostBack() === true) { $this->saveStep('Plugins.GettingStarted.Registration'); } // Save the action if they reviewed plugins if (strcasecmp($Sender->RequestMethod, 'plugins') == 0) { $this->saveStep('Plugins.GettingStarted.Plugins'); } // Save the action if they reviewed plugins if (strcasecmp($Sender->RequestMethod, 'managecategories') == 0) { $this->saveStep('Plugins.GettingStarted.Categories'); } // Add messages & their css on dashboard if (strcasecmp($Sender->RequestMethod, 'index') == 0) { $Sender->addCssFile('getting-started.css', 'plugins/GettingStarted'); $Session = Gdn::session(); $WelcomeMessage = '<div class="GettingStarted">' . anchor('×', '/dashboard/plugin/dismissgettingstarted/' . $Session->transientKey(), 'Dismiss') . "<h1>" . t("Here's how to get started:") . "</h1>" . '<ul> <li class="One' . (c('Plugins.GettingStarted.Dashboard', '0') == '1' ? ' Done' : '') . '"> <strong>' . anchor(t('Welcome to your Dashboard'), 'settings') . '</strong> <p>' . t('This is the administrative dashboard for your new community. Check out the configuration options to the left: from here you can configure how your community works. <b>Only users in the "Administrator" role can see this part of your community.</b>') . '</p> </li> <li class="Two' . (c('Plugins.GettingStarted.Discussions', '0') == '1' ? ' Done' : '') . '"> <strong>' . anchor(t("Where is your Community Forum?"), '/') . '</strong> <p>' . t('Access your community forum by clicking the "Visit Site" link on the top-left of this page, or by ') . anchor(t('clicking here'), '/') . t('. The community forum is what all of your users & customers will see when they visit ') . anchor(Gdn::request()->Url('/', true), Gdn::request()->Url('/', true)) . '.</p> </li> <li class="Three' . (c('Plugins.GettingStarted.Categories', '0') == '1' ? ' Done' : '') . '"> <strong>' . anchor(t('Organize your Categories'), 'vanilla/settings/managecategories') . '</strong> <p>' . t('Discussion categories are used to help your users organize their discussions in a way that is meaningful for your community.') . '</p> </li> <li class="Four' . (c('Plugins.GettingStarted.Profile', '0') == '1' ? ' Done' : '') . '"> <strong>' . anchor(t('Customize your Public Profile'), 'profile') . '</strong> <p>' . t('Everyone who signs up for your community gets a public profile page where they can upload a picture of themselves, manage their profile settings, and track cool things going on in the community. You should ') . anchor(t('customize your profile now'), 'profile') . '.</p> </li> <li class="Five' . (c('Plugins.GettingStarted.Discussion', '0') == '1' ? ' Done' : '') . '"> <strong>' . anchor(t('Start your First Discussion'), 'post/discussion') . '</strong> <p>' . t('Get the ball rolling in your community by ') . anchor(t('starting your first discussion'), 'post/discussion') . t(' now.') . '</p> </li> <li class="Six' . (c('Plugins.GettingStarted.Plugins', '0') == '1' ? ' Done' : '') . '"> <strong>' . anchor(t('Manage your Plugins'), 'settings/plugins') . '</strong> <p>' . t('Change the way your community works with plugins. We\'ve bundled popular plugins with the software, and there are more available online.') . '</p> </li> </ul> </div>'; $Sender->addAsset('Messages', $WelcomeMessage, 'WelcomeMessage'); } }
/** * Dismiss a message (per user). * * @since 2.0.0 * @access public */ public function dismiss($MessageID = '', $TransientKey = false) { $Session = Gdn::session(); if ($TransientKey !== false && $Session->validateTransientKey($TransientKey)) { $Prefs = $Session->getPreference('DismissedMessages', array()); $Prefs[] = $MessageID; $Session->setPreference('DismissedMessages', $Prefs); } if ($this->_DeliveryType === DELIVERY_TYPE_ALL) { redirect(getIncomingValue('Target', '/discussions')); } $this->render(); }
/** * * * @param array $Params The parameters passed into the function. * @param string $Content * @param object $Smarty The smarty object rendering the template. * @param bool $Repeat * @return string The url. */ function smarty_block_permission($Params, $Content, &$Smarty, &$Repeat) { // Only output on the closing tag. if (!$Repeat) { if (isset($Content)) { $Require = val('require', $Params); $HasPermission = Gdn::session()->checkPermission($Require); if ($HasPermission) { return $Content; } } } }
/** * * * @return string */ public function toString() { if (!Gdn::session()->checkPermission('Garden.Moderation.Manage')) { // Only moderators can view the reasons for being banned. return ''; } $this->getData(); if (empty($this->Data['Reasons'])) { return ''; } else { return parent::ToString(); } }
/** * Stash a value in the user's session, or unstash it if no value was provided to stash. * * Looks for Name and Value POST/GET variables to pass along to Gdn_Session. */ public function stash() { $this->deliveryType(DELIVERY_TYPE_BOOL); $this->deliveryMethod(DELIVERY_METHOD_JSON); $name = $this->Request->post('Name', ''); $value = $this->Request->post('Value', ''); if ($name !== '' && $value === null) { $response = Gdn::session()->getPublicStash($name, true); $this->setJson('Unstash', $response); } else { Gdn::session()->setPublicStash($name, $value); } $this->render(); }
/** * Allow admin to Change Author via discussion options. */ public function base_discussionOptions_handler($Sender, $Args) { $Discussion = $Args['Discussion']; if (Gdn::session()->checkPermission('Vanilla.Discussions.Edit', true, 'Category', $Discussion->PermissionCategoryID)) { $Label = t('Change Author'); $Url = "/discussion/author?discussionid={$Discussion->DiscussionID}"; // Deal with inconsistencies in how options are passed if (isset($Sender->Options)) { $Sender->Options .= wrap(anchor($Label, $Url, 'ChangeAuthor'), 'li'); } else { $Args['DiscussionOptions']['ChangeAuthor'] = ['Label' => $Label, 'Url' => $Url, 'Class' => 'ChangeAuthor']; } } }
/** * * * @return array|null|type */ public function getProviders() { $this->SQL->select('uap.*')->from('UserAuthenticationProvider uap'); if (Gdn::session()->isValid()) { $UserID = Gdn::session()->UserID; $this->SQL->select('ua.ForeignUserKey', '', 'UniqueID')->join('UserAuthentication ua', "uap.AuthenticationKey = ua.ProviderKey and ua.UserID = {$UserID}", 'left'); } $Data = $this->SQL->get()->resultArray(); $Data = Gdn_DataSet::index($Data, array('AuthenticationKey')); foreach ($Data as &$Row) { self::calculate($Row); } return $Data; }
/** * Delete a single draft. * * Redirects user back to Index unless DeliveryType is set. * * @since 2.0.0 * @access public * * @param int $DraftID Unique ID of draft to be deleted. * @param string $TransientKey Single-use hash to prove intent. */ public function delete($DraftID = '', $TransientKey = '') { $Form = Gdn::factory('Form'); $Session = Gdn::session(); if (is_numeric($DraftID) && $DraftID > 0) { $Draft = $this->DraftModel->getID($DraftID); } if ($Draft) { if ($Session->validateTransientKey($TransientKey) && (val('InsertUserID', $Draft) == $Session->UserID || checkPermission('Garden.Community.Manage'))) { // Delete the draft if (!$this->DraftModel->deleteID($DraftID)) { $Form->addError('Failed to delete draft'); } } else { throw permissionException('Garden.Community.Manage'); } } else { throw notFoundException('Draft'); } // Redirect if ($this->_DeliveryType === DELIVERY_TYPE_ALL) { $Target = GetIncomingValue('Target', '/drafts'); redirect($Target); } // Return any errors if ($Form->errorCount() > 0) { $this->setJson('ErrorMessage', $Form->errors()); } // Render default view $this->render(); }