public function testConstruction() { $e = new ReadOnlyError(); $this->assertEquals('readonly', $e->title); $this->assertEquals('readonlytext', $e->msg); $this->assertEquals(wfReadOnlyReason() ?: array(), $e->params); }
function __construct(Article $article) { // Set instance variables. $this->mArticle = $article; $this->mTitle = $article->getTitle(); $this->mApplicableTypes = $this->mTitle->getRestrictionTypes(); $this->mContext = $article->getContext(); // Check if the form should be disabled. // If it is, the form will be available in read-only to show levels. $this->mPermErrors = $this->mTitle->getUserPermissionsErrors('protect', $this->mContext->getUser(), $this->mContext->getRequest()->wasPosted() ? 'secure' : 'full'); if (wfReadOnly()) { $this->mPermErrors[] = ['readonlytext', wfReadOnlyReason()]; } $this->disabled = $this->mPermErrors != []; $this->disabledAttrib = $this->disabled ? ['disabled' => 'disabled'] : []; $this->loadData(); }
function __construct(Page $article) { global $wgUser; // Set instance variables. $this->mArticle = $article; $this->mTitle = $article->getTitle(); $this->mApplicableTypes = $this->mTitle->getRestrictionTypes(); // Check if the form should be disabled. // If it is, the form will be available in read-only to show levels. $this->mPermErrors = $this->mTitle->getUserPermissionsErrors('protect', $wgUser); if (wfReadOnly()) { $this->mPermErrors[] = array('readonlytext', wfReadOnlyReason()); } $this->disabled = $this->mPermErrors != array(); $this->disabledAttrib = $this->disabled ? array('disabled' => 'disabled') : array(); $this->loadData(); }
/** * Get status of database clusters * * Returns: * - clusters: associative array of cluster statuses * cluster name is the key and one of "ok", "warning", "critical" as a value * - messages: list of notices * - errors: list of errors */ public function databases() { $cluster = $this->getVal('cluster'); $clusters = $this->getAllClusters(); if ($cluster) { $clusters = array_intersect([$cluster], $clusters); } $this->clusters = $clusters; $this->testClusters(); $this->setVal('clusters', $this->status); if ($this->errors) { $this->setVal('errors', $this->errors); } if ($this->messages) { $this->setVal('messages', $this->messages); } $this->setVal('readWrite', ['status' => !wfReadOnly(), 'reason' => wfReadOnlyReason()]); }
/** * This function is the real heart of the entire Semantic Forms * extension. It handles two main actions: (1) displaying a form on the * screen, given a form definition and possibly page contents (if an * existing page is being edited); and (2) creating actual page * contents, if the form was already submitted by the user. * * It also does some related tasks, like figuring out the page name (if * only a page formula exists). */ function formHTML($form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $is_embedded = false) { global $wgRequest, $wgUser, $wgParser; global $sfgTabIndex; // used to represent the current tab index in the form global $sfgFieldNum; // used for setting various HTML IDs // initialize some variables $wiki_page = new SFWikiPage(); $sfgTabIndex = 1; $sfgFieldNum = 1; $source_page_matches_this_form = false; $form_page_title = null; $generated_page_name = $page_name_formula; // $form_is_partial is true if: // (a) 'partial' == 1 in the arguments // (b) 'partial form' is found in the form definition // in the latter case, it may remain false until close to the end of // the parsing, so we have to assume that it will become a possibility $form_is_partial = false; $new_text = ""; // If we have existing content and we're not in an active replacement // situation, preserve the original content. We do this because we want // to pass the original content on IF this is a partial form. // TODO: A better approach here would be to pass the revision ID of the // existing page content through the replace value, which would // minimize the html traffic and would allow us to do a concurrent // update check. For now, we pass it through a hidden text field. if (!$wgRequest->getCheck('partial')) { $original_page_content = $existing_page_content; } else { $original_page_content = null; if ($wgRequest->getCheck('sf_free_text')) { if (!isset($existing_page_content) || $existing_page_content == '') { $existing_page_content = $wgRequest->getVal('sf_free_text'); } $form_is_partial = true; } } // Disable all form elements if user doesn't have edit // permission - two different checks are needed, because // editing permissions can be set in different ways. // HACK - sometimes we don't know the page name in advance, but // we still need to set a title here for testing permissions. if ($is_embedded) { // If this is an embedded form (probably a 'RunQuery'), // just use the name of the actual page we're on. global $wgTitle; $this->mPageTitle = $wgTitle; } elseif ($is_query) { // We're in Special:RunQuery - just use that as the // title. global $wgTitle; $this->mPageTitle = $wgTitle; } elseif ($page_name === '' || $page_name === null) { $this->mPageTitle = Title::newFromText($wgRequest->getVal('namespace') . ":Semantic Forms permissions test"); } else { $this->mPageTitle = Title::newFromText($page_name); } global $wgOut; // Show previous set of deletions for this page, if it's been // deleted before. if (!$form_submitted && ($this->mPageTitle && !$this->mPageTitle->exists() && is_null($page_name_formula))) { $this->showDeletionLog($wgOut); } // Unfortunately, we can't just call userCan() here because, // since MW 1.16, it has a bug in which it ignores a setting of // "$wgEmailConfirmToEdit = true;". Instead, we'll just get the // permission errors from the start, and use those to determine // whether the page is editable. if (!$is_query) { // $userCanEditPage = ( $wgUser->isAllowed( 'edit' ) && $this->mPageTitle->userCan( 'edit' ) ); $permissionErrors = $this->mPageTitle->getUserPermissionsErrors('edit', $wgUser); // The handling of $wgReadOnly and $wgReadOnlyFile // has to be done separately. if (wfReadOnly()) { $permissionErrors = array(array('readonlytext', array(wfReadOnlyReason()))); } $userCanEditPage = count($permissionErrors) == 0; Hooks::run('sfUserCanEditPage', array($this->mPageTitle, &$userCanEditPage)); } $form_text = ""; if ($is_query || $userCanEditPage) { $form_is_disabled = false; // Show "Your IP address will be recorded" warning if // user is anonymous, and it's not a query. if ($wgUser->isAnon() && !$is_query) { // Based on code in MediaWiki's EditPage.php. $anonEditWarning = wfMessage('anoneditwarning', '{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}', '{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}')->parse(); $form_text .= Html::rawElement('div', array('id' => 'mw-anon-edit-warning', 'class' => 'warningbox'), $anonEditWarning); } } else { $form_is_disabled = true; $wgOut->setPageTitle(wfMessage('badaccess')->text()); $wgOut->addWikiText($wgOut->formatPermissionsErrorMessage($permissionErrors, 'edit')); $wgOut->addHTML("\n<hr />\n"); } // $oldParser = $wgParser; // $wgParser = unserialize( serialize( $oldParser ) ); // deep clone of parser if (!$wgParser->Options()) { $wgParser->Options(ParserOptions::newFromUser($wgUser)); } $wgParser->Title($this->mPageTitle); // This is needed in order to make sure $parser->mLinkHolders // is set. $wgParser->clearState(); $form_def = SFFormUtils::getFormDefinition($wgParser, $form_def, $form_id); // Turn form definition file into an array of sections, one for // each template definition (plus the first section). $form_def_sections = array(); $start_position = 0; $section_start = 0; $free_text_was_included = false; // Unencode any HTML-encoded representations of curly brackets and // pipes - this is a hack to allow for forms to include templates // that themselves contain form elements - the escaping was needed // to make sure that those elements don't get parsed too early. $form_def = str_replace(array('{', '|', '}'), array('{', '|', '}'), $form_def); // And another hack - replace the 'free text' standard input // with a field declaration to get it to be handled as a field. $form_def = str_replace('standard input|free text', 'field|<freetext>', $form_def); while ($brackets_loc = strpos($form_def, "{{{", $start_position)) { $brackets_end_loc = strpos($form_def, "}}}", $brackets_loc); $bracketed_string = substr($form_def, $brackets_loc + 3, $brackets_end_loc - ($brackets_loc + 3)); $tag_components = SFUtils::getFormTagComponents($bracketed_string); $tag_title = trim($tag_components[0]); if ($tag_title == 'for template' || $tag_title == 'end template') { // Create a section for everything up to here $section = substr($form_def, $section_start, $brackets_loc - $section_start); $form_def_sections[] = $section; $section_start = $brackets_loc; } $start_position = $brackets_loc + 1; } // end while $form_def_sections[] = trim(substr($form_def, $section_start)); // Cycle through the form definition file, and possibly an // existing article as well, finding template and field // declarations and replacing them with form elements, either // blank or pre-populated, as appropriate. $tif = null; // This array will keep track of all the replaced @<name>@ strings $placeholderFields = array(); for ($section_num = 0; $section_num < count($form_def_sections); $section_num++) { $start_position = 0; // the append is there to ensure that the original // array doesn't get modified; is it necessary? $section = " " . $form_def_sections[$section_num]; while ($brackets_loc = strpos($section, '{{{', $start_position)) { $brackets_end_loc = strpos($section, "}}}", $brackets_loc); $bracketed_string = substr($section, $brackets_loc + 3, $brackets_end_loc - ($brackets_loc + 3)); $tag_components = SFUtils::getFormTagComponents($bracketed_string); $tag_title = trim($tag_components[0]); // ===================================================== // for template processing // ===================================================== if ($tag_title == 'for template') { if ($tif) { $previous_template_name = $tif->getTemplateName(); } else { $previous_template_name = ''; } $template_name = str_replace('_', ' ', $tag_components[1]); $is_new_template = $template_name != $previous_template_name; if ($is_new_template) { $tif = SFTemplateInForm::newFromFormTag($tag_components); } // Remove template tag. $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); // If we are editing a page, and this // template can be found more than // once in that page, and multiple // values are allowed, repeat this // section. if ($source_is_page) { $tif->setPageRelatedInfo($existing_page_content); // Get the first instance of // this template on the page // being edited, even if there // are more. if ($tif->pageCallsThisTemplate()) { $tif->setFieldValuesFromPage($existing_page_content); $existing_template_text = $tif->getFullTextInPage(); // Now remove this template from the text being edited. // If this is a partial form, establish a new insertion point. if ($existing_page_content && $form_is_partial && $wgRequest->getCheck('partial')) { // If something already exists, set the new insertion point // to its position; otherwise just let it lie. if (strpos($existing_page_content, $existing_template_text) !== false) { $existing_page_content = str_replace("\n" . '{{{insertionpoint}}}', '', $existing_page_content); $existing_page_content = str_replace($existing_template_text, '{{{insertionpoint}}}', $existing_page_content); } } else { $existing_page_content = $this->strReplaceFirst($existing_template_text, '', $existing_page_content); } // If we've found a match in the source // page, there's a good chance that this // page was created with this form - note // that, so we don't send the user a warning. $source_page_matches_this_form = true; } } if ($form_submitted) { $tif->setFieldValuesFromSubmit(); } $tif->checkIfAllInstancesPrinted($form_submitted, $source_is_page); if (!$tif->allInstancesPrinted()) { $wiki_page->addTemplate($tif); } // ===================================================== // end template processing // ===================================================== } elseif ($tag_title == 'end template') { if ($source_is_page) { // Add any unhandled template fields // in the page as hidden variables. $form_text .= SFFormUtils::unhandledFieldsHTML($tif); } // Remove this tag from the $section variable. $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); $tif = null; // ===================================================== // field processing // ===================================================== } elseif ($tag_title == 'field') { // If the template is null, that (hopefully) // means we're handling the free text field. // Make the template a dummy variable. if ($tif == null) { $tif = new SFTemplateInForm(); } // We get the field name both here // and in the SFFormField constructor, // because SFFormField isn't equipped // to deal with the <freetext> hack, // among others. $field_name = trim($tag_components[1]); $form_field = SFFormField::newFromFormFieldTag($tag_components, $tif, $form_is_disabled); $cur_value = $form_field->getCurrentValue($tif->getValuesFromSubmit(), $form_submitted, $source_is_page); if ($form_field->holdsTemplate()) { $placeholderFields[] = self::placeholderFormat($tif->getTemplateName(), $field_name); } // If the user is editing a page, and that page contains a call to // the template being processed, get the current field's value // from the template call if ($source_is_page && ($tif->getFullTextInPage() != '' && !$form_submitted)) { if ($tif->hasValueFromPageForField($field_name)) { // Get value, and remove it, // so that at the end we // can have a list of all // the fields that weren't // handled by the form. $cur_value = $tif->getAndRemoveValueFromPageForField($field_name); // If the field is a placeholder, the contents of this template // parameter should be treated as elements parsed by an another // multiple template form. // By putting that at the very end of the parsed string, we'll // have it processed as a regular multiple template form. if ($form_field->holdsTemplate()) { $existing_page_content .= $cur_value; } } elseif (isset($cur_value) && !empty($cur_value)) { // Do nothing. } else { $cur_value = ''; } } // Handle the free text field. if ($field_name == '<freetext>') { // Add placeholders for the free text in both the form and // the page, using <free_text> tags - once all the free text // is known (at the end), it will get substituted in. if ($form_field->isHidden()) { $new_text = Html::hidden('sf_free_text', '!free_text!'); } else { $sfgTabIndex++; $sfgFieldNum++; if ($cur_value === '' || is_null($cur_value)) { $default_value = '!free_text!'; } else { $default_value = $cur_value; } $new_text = SFTextAreaInput::getHTML($default_value, 'sf_free_text', false, $form_is_disabled || $form_field->isRestricted(), $form_field->getFieldArgs()); if ($form_field->hasFieldArg('edittools')) { // borrowed from EditPage::showEditTools() $edittools_text = $wgParser->recursiveTagParse(wfMessage('edittools', array('content'))->text()); $new_text .= <<<END \t\t<div class="mw-editTools"> \t\t{$edittools_text} \t\t</div> END; } } $free_text_was_included = true; $wiki_page->addFreeTextSection(); } if ($tif->getTemplateName() === '' || $field_name == '<freetext>') { $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); } else { if (is_array($cur_value)) { // @TODO - is this code ever called? $delimiter = $form_field->getFieldArg('is_list'); // first, check if it's a list if (array_key_exists('is_list', $cur_value) && $cur_value['is_list'] == true) { $cur_value_in_template = ""; foreach ($cur_value as $key => $val) { if ($key !== "is_list") { if ($cur_value_in_template != "") { $cur_value_in_template .= $delimiter . " "; } $cur_value_in_template .= $val; } } } else { // If it's not a list, it's probably from a checkbox or date input - // convert the values into a string. $cur_value_in_template = self::getStringFromPassedInArray($cur_value, $delimiter); } } else { // value is not an array $cur_value_in_template = $cur_value; } // If we're creating the page name from a formula based on // form values, see if the current input is part of that formula, // and if so, substitute in the actual value. if ($form_submitted && $generated_page_name !== '') { // This line appears to be unnecessary. // $generated_page_name = str_replace('.', '_', $generated_page_name); $generated_page_name = str_replace(' ', '_', $generated_page_name); $escaped_input_name = str_replace(' ', '_', $form_field->getInputName()); $generated_page_name = str_ireplace("<{$escaped_input_name}>", $cur_value_in_template, $generated_page_name); // Once the substitution is done, replace underlines back // with spaces. $generated_page_name = str_replace('_', ' ', $generated_page_name); } // Call hooks - unfortunately this has to be split into two // separate calls, because of the different variable names in // each case. if ($form_submitted) { Hooks::run('sfCreateFormField', array(&$form_field, &$cur_value_in_template, true)); } else { if (!empty($cur_value) && ($form_field->hasFieldArg('mapping template') || $form_field->hasFieldArg('mapping property') || $form_field->hasFieldArg('mapping cargo table') && $form_field->hasFieldArg('mapping cargo field'))) { $cur_value = SFUtils::valuesToLabels($cur_value, $delimiter, $form_field->getPossibleValues()); } Hooks::run('sfCreateFormField', array(&$form_field, &$cur_value, false)); } // if this is not part of a 'multiple' template, increment the // global tab index (used for correct tabbing) if (!$form_field->hasFieldArg('part_of_multiple')) { $sfgTabIndex++; } // increment the global field number regardless $sfgFieldNum++; // If the field is a date field, and its default value was set // to 'now', and it has no current value, set $cur_value to be // the current date. if ($form_field->getDefaultValue() == 'now' && ($cur_value == '' || $cur_value == 'now')) { $input_type = $form_field->getInputType(); if ($input_type == 'date' || $input_type == 'datetime' || $input_type == 'year' || $input_type == '' && $form_field->getTemplateField()->getPropertyType() == '_dat') { $cur_value_in_template = self::getStringForCurrentTime($input_type == 'datetime', $form_field->hasFieldArg('include timezone')); } } // If the field is a text field, and its default value was set // to 'current user', and it has no current value, set $cur_value // to be the current user. if ($form_field->getDefaultValue() == 'current user' && ($cur_value === '' || $cur_value == 'current user')) { $cur_value_in_template = $wgUser->getName(); $cur_value = $cur_value_in_template; } // If all instances have been // printed, that means we're // now printing a "starter" // div - set the current value // to null. // (Ideally it wouldn't get // set at all, but that seems a // little harder.) if ($tif->allInstancesPrinted()) { $cur_value = null; } $new_text = $this->formFieldHTML($form_field, $cur_value); $new_text .= $form_field->additionalHTMLForInput($cur_value, $field_name, $tif->getTemplateName()); if ($new_text) { $wiki_page->addTemplateParam($template_name, $tif->getInstanceNum(), $field_name, $cur_value_in_template); $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); } else { $start_position = $brackets_end_loc; } } // ===================================================== // standard input processing // ===================================================== } elseif ($tag_title == 'standard input') { // handle all the possible values $input_name = $tag_components[1]; $input_label = null; $attr = array(); // if it's a query, ignore all standard inputs except run query if ($is_query && $input_name != 'run query' || !$is_query && $input_name == 'run query') { $new_text = ""; $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); continue; } // set a flag so that the standard 'form bottom' won't get displayed $this->standardInputsIncluded = true; // cycle through the other components $is_checked = false; for ($i = 2; $i < count($tag_components); $i++) { $component = $tag_components[$i]; $sub_components = array_map('trim', explode('=', $component)); if (count($sub_components) == 1) { if ($sub_components[0] == 'checked') { $is_checked = true; } } elseif (count($sub_components) == 2) { switch ($sub_components[0]) { case 'label': $input_label = $wgParser->recursiveTagParse($sub_components[1]); break; case 'class': case 'style': $attr[$sub_components[0]] = $sub_components[1]; break; } } } if ($input_name == 'summary') { $value = $wgRequest->getVal('wpSummary'); $new_text = SFFormUtils::summaryInputHTML($form_is_disabled, $input_label, $attr, $value); } elseif ($input_name == 'minor edit') { $is_checked = $wgRequest->getCheck('wpMinoredit'); $new_text = SFFormUtils::minorEditInputHTML($form_submitted, $form_is_disabled, $is_checked, $input_label, $attr); } elseif ($input_name == 'watch') { $is_checked = $wgRequest->getCheck('wpWatchthis'); $new_text = SFFormUtils::watchInputHTML($form_submitted, $form_is_disabled, $is_checked, $input_label, $attr); } elseif ($input_name == 'save') { $new_text = SFFormUtils::saveButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'save and continue') { $new_text = SFFormUtils::saveAndContinueButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'preview') { $new_text = SFFormUtils::showPreviewButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'changes') { $new_text = SFFormUtils::showChangesButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'cancel') { $new_text = SFFormUtils::cancelLinkHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'run query') { $new_text = SFFormUtils::runQueryButtonHTML($form_is_disabled, $input_label, $attr); } $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); // ===================================================== // for section processing // ===================================================== } elseif ($tag_title == 'section') { $section_name = trim($tag_components[1]); $page_section_in_form = SFPageSection::newFromFormTag($tag_components); // Split the existing page contents into the textareas in the form. $default_value = ""; $section_start_loc = 0; if ($source_is_page && $existing_page_content !== null) { // For the last section of the page, there is no trailing newline in // $existing_page_content, but the code below expects it. This code // ensures that there is always trailing newline. T72202 if (substr($existing_page_content, -1) !== "\n") { $existing_page_content .= "\n"; } $equalsSigns = str_pad('', $page_section_in_form->getSectionLevel(), '='); $searchStr = '/^' . preg_quote($equalsSigns, '/') . '[ ]*?' . preg_quote($section_name, '/') . '[ ]*?' . preg_quote($equalsSigns, '/') . '$/m'; if (preg_match($searchStr, $existing_page_content, $matches, PREG_OFFSET_CAPTURE)) { $section_start_loc = $matches[0][1]; $header_text = $matches[0][0]; $existing_page_content = str_replace($header_text, '', $existing_page_content); } else { $section_start_loc = 0; } $section_end_loc = -1; // get the position of the next template or section defined in the form $next_section_start_loc = strpos($section, '{{{', $brackets_end_loc); if ($next_section_start_loc == false) { $section_end_loc = strpos($existing_page_content, '{{', $section_start_loc); } else { $next_section_end_loc = strpos($section, '}}}', $next_section_start_loc); $bracketed_string_next_section = substr($section, $next_section_start_loc + 3, $next_section_end_loc - ($next_section_start_loc + 3)); $tag_components_next_section = SFUtils::getFormTagComponents($bracketed_string_next_section); $tag_title_next_section = trim($tag_components_next_section[0]); if ($tag_title_next_section == 'section') { if (preg_match('/(^={1,6}[ ]*?' . $tag_components_next_section[1] . '[ ]*?={1,6}\\s*?$)/m', $existing_page_content, $matches, PREG_OFFSET_CAPTURE)) { $section_end_loc = $matches[0][1]; } } } if ($section_end_loc === -1) { $section_text = $existing_page_content; $existing_page_content = ''; } else { $section_text = substr($existing_page_content, $section_start_loc, $section_end_loc - $section_start_loc); $existing_page_content = substr($existing_page_content, $section_end_loc); } } // If input is from the form. if (!$source_is_page && $wgRequest) { $text_per_section = $wgRequest->getArray('_section'); $section_text = $text_per_section[trim($section_name)]; $wiki_page->addSection($section_name, $page_section_in_form->getSectionLevel(), $section_text); } $section_text = trim($section_text); // Set input name for query string. $input_name = '_section' . '[' . trim($section_name) . ']'; $other_args = $page_section_in_form->getSectionArgs(); $other_args['isSection'] = true; if ($page_section_in_form->isMandatory()) { $other_args['mandatory'] = true; } if ($page_section_in_form->isHidden()) { $form_section_text = Html::hidden($input_name, $section_text); } else { $form_section_text = SFTextAreaInput::getHTML($section_text, $input_name, false, $form_is_disabled || $page_section_in_form->isRestricted(), $other_args); } $section = substr_replace($section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); // ===================================================== // page info processing // ===================================================== } elseif ($tag_title == 'info') { // TODO: Generate an error message if this is included more than once foreach (array_slice($tag_components, 1) as $component) { $sub_components = array_map('trim', explode('=', $component, 2)); // Tag names are case-insensitive $tag = strtolower($sub_components[0]); if ($tag == 'create title' || $tag == 'add title') { // Handle this only if // we're adding a page. if (!$is_query && !$this->mPageTitle->exists()) { $form_page_title = $sub_components[1]; } } elseif ($tag == 'edit title') { // Handle this only if // we're editing a page. if (!$is_query && $this->mPageTitle->exists()) { $form_page_title = $sub_components[1]; } } elseif ($tag == 'query title') { // Handle this only if // we're in 'RunQuery'. if ($is_query) { $form_page_title = $sub_components[1]; } } elseif ($tag == 'partial form') { $form_is_partial = true; // replacement pages may have minimal matches... $source_page_matches_this_form = true; } elseif ($tag == 'includeonly free text' || $tag == 'onlyinclude free text') { $wiki_page->makeFreeTextOnlyInclude(); } elseif ($tag == 'query form at top') { // TODO - this should be made a field of // some non-static class that actually // prints the form, instead of requiring // a global variable. global $sfgRunQueryFormAtTop; $sfgRunQueryFormAtTop = true; } } $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); // ===================================================== // default outer level processing // ===================================================== } else { // Tag is not one of the three allowed values - // ignore the tag. $start_position = $brackets_end_loc; } // end if } // end while if ($tif && (!$tif->allowsMultiple() || $tif->allInstancesPrinted())) { $template_text = $wiki_page->createTemplateCallsForTemplateName($tif->getTemplateName()); // If there is a placeholder in the text, we // know that we are doing a replace. if ($existing_page_content && strpos($existing_page_content, '{{{insertionpoint}}}', 0) !== false) { $existing_page_content = preg_replace('/\\{\\{\\{insertionpoint\\}\\}\\}(\\r?\\n?)/', preg_replace('/\\}\\}/m', '}�', preg_replace('/\\{\\{/m', '�{', $template_text)) . "\n{{{insertionpoint}}}", $existing_page_content); // Otherwise, if it's a partial form, we have to add the new // text somewhere. } elseif ($form_is_partial && $wgRequest->getCheck('partial')) { $existing_page_content = preg_replace('/\\}\\}/m', '}�', preg_replace('/\\{\\{/m', '�{', $template_text)) . "{{{insertionpoint}}}" . $existing_page_content; } } if ($tif && $tif->allowsMultiple()) { if ($tif->getInstanceNum() == 0) { $multipleTemplateHTML = $this->multipleTemplateStartHTML($tif); } else { $multipleTemplateHTML = ''; } if (!$tif->allInstancesPrinted()) { $multipleTemplateHTML .= $this->multipleTemplateInstanceHTML($tif, $form_is_disabled, $section); } else { $multipleTemplateHTML .= $this->multipleTemplateEndHTML($tif, $form_is_disabled, $section); } $placeholder = $tif->getPlaceholder(); if ($placeholder != null) { $multipleTemplateHTML .= self::makePlaceholderInFormHTML($placeholder); } if ($tif->allInstancesPrinted() && $tif->getLabel() != null) { $multipleTemplateHTML .= "</fieldset>\n"; } if ($placeholder == null) { // The normal process. $form_text .= $multipleTemplateHTML; } else { // The template text won't be appended // at the end of the template like for // usual multiple template forms. // The HTML text will instead be stored in // the $multipleTemplateHTML variable, // and then added in the right // @insertHTML_".$placeHolderField."@"; position // Optimization: actually, instead of // separating the processes, the usual // multiple template forms could also be // handled this way if a fitting // placeholder tag was added. // We replace the HTML into the current // placeholder tag, but also add another // placeholder tag, to keep track of it. $form_text = str_replace(self::makePlaceholderInFormHTML($placeholder), $multipleTemplateHTML, $form_text); } if (!$tif->allInstancesPrinted()) { // This will cause the section to be // re-parsed on the next go. $section_num--; $tif->incrementInstanceNum(); } } else { $form_text .= $section; } } // end for // Cleanup - everything has been browsed. // Remove all the remaining placeholder // tags in the HTML and wiki-text. foreach ($placeholderFields as $stringToReplace) { // Remove the @<insertHTML>@ tags from the generated // HTML form. $form_text = str_replace(self::makePlaceholderInFormHTML($stringToReplace), '', $form_text); } // If it wasn't included in the form definition, add the // 'free text' input as a hidden field at the bottom. if (!$free_text_was_included) { $form_text .= Html::hidden('sf_free_text', '!free_text!'); } // Get free text, and add to page data, as well as retroactively // inserting it into the form. // If $form_is_partial is true then either: // (a) we're processing a replacement (param 'partial' == 1) // (b) we're sending out something to be replaced (param 'partial' is missing) if ($form_is_partial) { if (!$wgRequest->getCheck('partial')) { $free_text = $original_page_content; } else { $free_text = null; $existing_page_content = preg_replace(array('/�\\{/m', '/\\}�/m'), array('{{', '}}'), $existing_page_content); $existing_page_content = str_replace('{{{insertionpoint}}}', '', $existing_page_content); } $form_text .= Html::hidden('partial', 1); } elseif ($source_is_page) { // If the page is the source, free_text will just be // whatever in the page hasn't already been inserted // into the form. $free_text = trim($existing_page_content); // or get it from a form submission } elseif ($wgRequest->getCheck('sf_free_text')) { $free_text = $wgRequest->getVal('sf_free_text'); if (!$free_text_was_included) { $wiki_page->addFreeTextSection(); } } else { $free_text = null; } if ($wiki_page->freeTextOnlyInclude()) { $free_text = str_replace("<onlyinclude>", '', $free_text); $free_text = str_replace("</onlyinclude>", '', $free_text); $free_text = trim($free_text); } $page_text = ''; // The first hook here is deprecated. Use the second. // Note: Hooks::run can take a third argument which indicates // a deprecated hook, but it expects a MediaWiki version, not // an extension version. Hooks::run('sfModifyFreeTextField', array(&$free_text, $existing_page_content)); Hooks::run('sfBeforeFreeTextSubstitution', array(&$free_text, $existing_page_content, &$page_text)); // Now that we have it, add free text to the page, and // substitute it into the form. if ($form_submitted) { $wiki_page->setFreeText($free_text); $page_text = $wiki_page->createPageText(); } $escaped_free_text = Sanitizer::safeEncodeAttribute($free_text); $form_text = str_replace('!free_text!', $escaped_free_text, $form_text); // Add a warning in, if we're editing an existing page and that // page appears to not have been created with this form. if (!$is_query && is_null($page_name_formula) && $this->mPageTitle->exists() && $existing_page_content !== '' && !$source_page_matches_this_form) { $form_text = "\t" . '<div class="warningbox">' . wfMessage('sf_formedit_formwarning', $this->mPageTitle->getFullURL())->text() . "</div>\n<br clear=\"both\" />\n" . $form_text; } // Add form bottom, if no custom "standard inputs" have been defined. if (!$this->standardInputsIncluded) { if ($is_query) { $form_text .= SFFormUtils::queryFormBottom($form_is_disabled); } else { $form_text .= SFFormUtils::formBottom($form_submitted, $form_is_disabled); } } if (!$is_query) { $form_text .= Html::hidden('wpStarttime', wfTimestampNow()); $article = new Article($this->mPageTitle, 0); $form_text .= Html::hidden('wpEdittime', $article->getTimestamp()); $form_text .= Html::hidden('wpEditToken', $wgUser->getEditToken()); } $form_text .= "\t</form>\n"; $wgParser->replaceLinkHolders($form_text); Hooks::run('sfRenderingEnd', array(&$form_text)); // Add general Javascript code. $javascript_text = ""; Hooks::run('sfAddJavascriptToForm', array(&$javascript_text)); // Send the autocomplete values to the browser, along with the // mappings of which values should apply to which fields. // If doing a replace, the page text is actually the modified // original page. if ($wgRequest->getCheck('partial')) { $page_text = $existing_page_content; } if (!$is_embedded) { $form_page_title = $wgParser->recursiveTagParse(str_replace("{{!}}", "|", $form_page_title)); } else { $form_page_title = null; } // If the form has already been submitted, i.e. this is just // the redirect page, get rid of all the Javascript, to avoid // JS errors. if ($form_submitted) { $javascript_text = ''; } // $wgParser = $oldParser; return array($form_text, $javascript_text, $page_text, $form_page_title, $generated_page_name); }
protected function appendGeneralInfo($property) { global $wgContLang, $wgDisableLangConversion, $wgDisableTitleConversion; $data = array(); $mainPage = Title::newMainPage(); $data['mainpage'] = $mainPage->getPrefixedText(); $data['base'] = wfExpandUrl($mainPage->getFullURL(), PROTO_CURRENT); $data['sitename'] = $GLOBALS['wgSitename']; // wgLogo can either be a relative or an absolute path // make sure we always return an absolute path $data['logo'] = wfExpandUrl($GLOBALS['wgLogo'], PROTO_RELATIVE); $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}"; $data['phpversion'] = phpversion(); $data['phpsapi'] = PHP_SAPI; $data['dbtype'] = $GLOBALS['wgDBtype']; $data['dbversion'] = $this->getDB()->getServerVersion(); $allowFrom = array(''); $allowException = true; if (!$GLOBALS['wgAllowExternalImages']) { if ($GLOBALS['wgEnableImageWhitelist']) { $data['imagewhitelistenabled'] = ''; } $allowFrom = $GLOBALS['wgAllowExternalImagesFrom']; $allowException = !empty($allowFrom); } if ($allowException) { $data['externalimages'] = (array) $allowFrom; $this->getResult()->setIndexedTagName($data['externalimages'], 'prefix'); } if (!$wgDisableLangConversion) { $data['langconversion'] = ''; } if (!$wgDisableTitleConversion) { $data['titleconversion'] = ''; } if ($wgContLang->linkPrefixExtension()) { $linkPrefixCharset = $wgContLang->linkPrefixCharset(); $data['linkprefixcharset'] = $linkPrefixCharset; // For backwards compatability $data['linkprefix'] = "/^((?>.*[^{$linkPrefixCharset}]|))(.+)\$/sDu"; } else { $data['linkprefixcharset'] = ''; $data['linkprefix'] = ''; } $linktrail = $wgContLang->linkTrail(); if ($linktrail) { $data['linktrail'] = $linktrail; } else { $data['linktrail'] = ''; } $git = SpecialVersion::getGitHeadSha1($GLOBALS['IP']); if ($git) { $data['git-hash'] = $git; } else { $svn = SpecialVersion::getSvnRevision($GLOBALS['IP']); if ($svn) { $data['rev'] = $svn; } } // 'case-insensitive' option is reserved for future $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive'; $data['lang'] = $GLOBALS['wgLanguageCode']; $fallbacks = array(); foreach ($wgContLang->getFallbackLanguages() as $code) { $fallbacks[] = array('code' => $code); } $data['fallback'] = $fallbacks; $this->getResult()->setIndexedTagName($data['fallback'], 'lang'); if ($wgContLang->hasVariants()) { $variants = array(); foreach ($wgContLang->getVariants() as $code) { $variants[] = array('code' => $code, 'name' => $wgContLang->getVariantname($code)); } $data['variants'] = $variants; $this->getResult()->setIndexedTagName($data['variants'], 'lang'); } if ($wgContLang->isRTL()) { $data['rtl'] = ''; } $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding(); if (wfReadOnly()) { $data['readonly'] = ''; $data['readonlyreason'] = wfReadOnlyReason(); } if ($GLOBALS['wgEnableWriteAPI']) { $data['writeapi'] = ''; } $tz = $GLOBALS['wgLocaltimezone']; $offset = $GLOBALS['wgLocalTZoffset']; if (is_null($tz)) { $tz = 'UTC'; $offset = 0; } elseif (is_null($offset)) { $offset = 0; } $data['timezone'] = $tz; $data['timeoffset'] = intval($offset); $data['articlepath'] = $GLOBALS['wgArticlePath']; $data['scriptpath'] = $GLOBALS['wgScriptPath']; $data['script'] = $GLOBALS['wgScript']; $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath']; $data['server'] = $GLOBALS['wgServer']; $data['wikiid'] = wfWikiID(); $data['time'] = wfTimestamp(TS_ISO_8601, time()); if ($GLOBALS['wgMiserMode']) { $data['misermode'] = ''; } $data['maxuploadsize'] = UploadBase::getMaxUploadSize(); $data['thumblimits'] = $GLOBALS['wgThumbLimits']; $this->getResult()->setIndexedTagName($data['thumblimits'], 'limit'); $data['imagelimits'] = array(); $this->getResult()->setIndexedTagName($data['imagelimits'], 'limit'); foreach ($GLOBALS['wgImageLimits'] as $k => $limit) { $data['imagelimits'][$k] = array('width' => $limit[0], 'height' => $limit[1]); } if (!empty($GLOBALS['wgFavicon'])) { // wgFavicon can either be a relative or an absolute path // make sure we always return an absolute path $data['favicon'] = wfExpandUrl($GLOBALS['wgFavicon'], PROTO_RELATIVE); } wfRunHooks('APIQuerySiteInfoGeneralInfo', array($this, &$data)); return $this->getResult()->addValue('query', $property, $data); }
private function sendMessage($mSender, $mText, $formData) { global $wgExternalSharedDB, $wgStatsDB, $wgUser; $result = array('msgId' => null, 'errMsg' => null); $dbInsertResult = false; $mWikiId = null; $mLang = $formData['mLang']; if (is_array($mLang)) { $mLang = implode(',', $mLang); } $mRecipientId = $formData['sendModeUsers'] != 'USER' ? null : $wgUser->idFromName($formData['userName']); $mWikiName = $formData['wikiName']; $mRecipientName = $formData['userName']; $mGroupName = $formData['groupName'] == '' ? $formData['groupNameS'] : $formData['groupName']; $mSendModeWikis = $formData['sendModeWikis']; $mSendModeUsers = $formData['sendModeUsers']; $mHubId = $formData['hubId']; $mClusterId = $formData['clusterId']; $mUserNamesArr = array_unique(explode("\n", $formData['listUserNames'])); $mWikiNamesArr = array_unique(explode("\n", $formData['listWikiNames'])); //remove unnecessary data switch ($mSendModeWikis) { case 'ALL': $mWikiName = ''; $mHubId = null; $mClusterId = null; break; case 'HUB': $mWikiName = ''; $mClusterId = null; break; case 'CLUSTER': $mWikiName = ''; $mHubId = null; break; case 'WIKI': $mHubId = null; $mClusterId = null; break; case 'WIKIS': $mWikiName = count($mWikiNamesArr) . ' wikis'; $mHubId = null; $mClusterId = null; break; case 'CREATED': $mWikiName = MSG_WIKI_CREATION_DATE; $mHubId = null; $mClusterId = null; break; } switch ($mSendModeUsers) { case 'ALL': case 'ACTIVE': $mRecipientName = ''; $mGroupName = ''; break; case 'GROUP': $mRecipientName = ''; break; case 'USER': $mGroupName = ''; $mLang = MSG_LANG_ALL; break; case 'USERS': $mRecipientName = count($mUserNamesArr) . ' users'; $mGroupName = ''; $mLang = MSG_LANG_ALL; break; case 'ANONS': $mRecipientName = MSG_RECIPIENT_ANON; $mGroupName = ''; break; case 'REGISTRATION': $mRecipientName = ''; $mGroupName = ''; break; case 'EDITCOUNT': $mRecipientName = ''; $mGroupName = ''; break; } $sendToAll = $mSendModeWikis == 'ALL' && $mSendModeUsers == 'ALL'; $tmpWikiName = false; if ($mSendModeWikis == 'WIKI' && $mWikiName != '') { $tmpWikiName = $mWikiName; } if ($tmpWikiName) { $wikiDomains = array('', '.wikia.com'); foreach ($wikiDomains as $wikiDomain) { if (!is_null($mWikiId = WikiFactory::DomainToID($tmpWikiName . $wikiDomain))) { break; } } } $validDateTime = true; if ($formData['expireTimeS'] !== '') { $timestamp = wfTimestamp(TS_UNIX, $formData['expireTimeS']); if (!$timestamp) { $validDateTime = false; } $mExpire = wfTimestamp(TS_DB, $timestamp); } else { //null => expire never $mExpire = $formData['expireTime'] != '0' ? date('Y-m-d H:i:s', strtotime(ctype_digit($formData['expireTime']) ? " +{$formData['expireTime']} day" : ' +' . substr($formData['expireTime'], 0, -1) . ' hour')) : null; } if ($mSendModeWikis === 'CREATED') { $timestamp = wfTimestamp(TS_UNIX, $formData['wikiCreationDateOne']); if (!$timestamp) { $validDateTime = false; } $formData['wikiCreationDateOne'] = wfTimestamp(TS_DB, $timestamp); if ($formData['wikiCreationDateOption'] === 'between') { if ($formData['wikiCreationDateTwo'] !== '') { $timestamp = wfTimestamp(TS_UNIX, $formData['wikiCreationDateTwo']); if (!$timestamp) { $validDateTime = false; } $formData['wikiCreationDateTwo'] = wfTimestamp(TS_DB, $timestamp); } else { $validDateTime = false; } } } if ($mSendModeUsers === 'REGISTRATION') { $timestamp = wfTimestamp(TS_UNIX, $formData['registrationDateOne']); if (!$timestamp) { $validDateTime = false; } $formData['registrationDateOne'] = wfTimestamp(TS_MW, $timestamp); if ($formData['registrationDateOption'] === 'between') { if ($formData['registrationDateTwo'] !== '') { $timestamp = wfTimestamp(TS_UNIX, $formData['registrationDateTwo']); if (!$timestamp) { $validDateTime = false; } $formData['registrationDateTwo'] = wfTimestamp(TS_MW, $timestamp); } else { $validDateTime = false; } } } if (wfReadOnly()) { $reason = wfReadOnlyReason(); $result['errMsg'] = wfMsg('readonlytext', $reason); } elseif ($mText == '') { $result['errMsg'] = wfMsg('swm-error-empty-message'); } elseif (mb_strlen($mText) > 500) { $result['errMsg'] = wfMsg('swm-error-long-message'); } elseif ($mSendModeWikis == 'WIKI' && is_null($mWikiId)) { //this wiki doesn't exist $result['errMsg'] = wfMsg('swm-error-no-such-wiki'); } elseif ($mSendModeUsers == 'WIKIS' && empty($formData['listWikiNames'])) { $result['errMsg'] = wfMsg('swm-error-no-wiki-list'); } elseif ($mSendModeUsers == 'USER' && !User::idFromName($mRecipientName)) { $result['errMsg'] = wfMsg('swm-error-no-such-user'); } elseif ($mSendModeUsers == 'USERS' && empty($formData['listUserNames'])) { $result['errMsg'] = wfMsg('swm-error-no-user-list'); } elseif (!$validDateTime) { $result['errMsg'] = wfMsg('swm-error-invalid-time'); } elseif ($mSendModeUsers === 'REGISTRATION' && $formData['registrationDateOption'] === 'between' && $formData['registrationDateTwo'] <= $formData['registrationDateOne']) { $result['errMsg'] = wfMsg('swm-error-registered-tobeforefrom'); } elseif ($mSendModeWikis === 'CREATED' && $formData['wikiCreationDateOption'] === 'between' && $formData['wikiCreationDateTwo'] <= $formData['wikiCreationDateOne']) { $result['errMsg'] = wfMsg('swm-error-created-tobeforefrom'); } elseif ($mSendModeUsers === 'EDITCOUNT' && (!is_numeric($formData['editCountOne']) || $formData['editCountOption'] === 'between' && !is_numeric($formData['editCountTwo']))) { $result['errMsg'] = wfMsg('swm-error-editcount-notnumber'); } elseif ($mSendModeUsers === 'EDITCOUNT' && $formData['editCountOption'] === 'between' && $formData['editCountTwo'] <= $formData['editCountOne']) { $result['errMsg'] = wfMsg('swm-error-editcount-tolessthanfrom'); } else { global $wgParser, $wgUser; $title = Title::newFromText(uniqid('tmp')); $options = ParserOptions::newFromUser($wgUser); //Parse some wiki markup [eg. ~~~~] $mText = $wgParser->preSaveTransform($mText, $title, $wgUser, $options); $DB = wfGetDB(DB_MASTER, array(), $wgExternalSharedDB); $dbResult = (bool) $DB->Query('INSERT INTO ' . MSG_TEXT_DB . ' (msg_sender_id, msg_text, msg_mode, msg_expire, msg_recipient_name, msg_group_name, msg_wiki_name, msg_hub_id, msg_lang, msg_cluster_id)' . ' VALUES (' . $DB->AddQuotes($mSender->GetID()) . ', ' . $DB->AddQuotes($mText) . ', ' . ($sendToAll ? MSG_MODE_ALL : MSG_MODE_SELECTED) . ', ' . $DB->AddQuotes($mExpire) . ', ' . $DB->AddQuotes($mRecipientName) . ', ' . $DB->AddQuotes($mGroupName) . ', ' . $DB->AddQuotes($mWikiName) . ', ' . $DB->AddQuotes($mHubId) . ' , ' . $DB->AddQuotes($mLang) . ' , ' . $DB->AddQuotes($mClusterId) . ');', __METHOD__); if ($dbResult) { $dbInsertResult = true; $result['msgId'] = $DB->insertId(); if (is_null($mWikiId)) { $mWikiId = 0; } if ($mSendModeUsers == 'USER') { if (!is_null($mRecipientId) && !is_null($result['msgId'])) { $dbResult = (bool) $DB->Query('INSERT INTO ' . MSG_STATUS_DB . ' (msg_wiki_id, msg_recipient_id, msg_id, msg_status)' . ' VALUES (' . $DB->AddQuotes($mWikiId) . ', ' . $DB->AddQuotes($mRecipientId) . ', ' . $DB->AddQuotes($result['msgId']) . ', ' . MSG_STATUS_UNSEEN . ');', __METHOD__); $dbInsertResult &= $dbResult; } } elseif ($mSendModeWikis != 'WIKIS' && $mSendModeWikis != 'CREATED' && $mSendModeUsers == 'ANONS') { if (!is_null($result['msgId'])) { $dbResult = (bool) $DB->query('INSERT INTO ' . MSG_STATUS_DB . ' (msg_wiki_id, msg_recipient_id, msg_id, msg_status)' . ' VALUES (' . $DB->addQuotes($mWikiId) . ', 0, ' . $DB->addQuotes($result['msgId']) . ', ' . MSG_STATUS_UNSEEN . ');', __METHOD__); $dbInsertResult &= $dbResult; } } elseif ($mSendModeUsers == 'USERS') { $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'userNames' => $mUserNamesArr, 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); } else { switch ($mSendModeWikis) { case 'ALL': switch ($mSendModeUsers) { case 'ALL': break; case 'ACTIVE': case 'GROUP': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; case 'REGISTRATION': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'regOption' => $formData['registrationDateOption'], 'regStartDate' => $formData['registrationDateOne'], 'regEndDate' => $formData['registrationDateTwo'], 'senderId' => $mSender->getID(), 'senderName' => $mSender->getName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; case 'EDITCOUNT': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'editCountOption' => $formData['editCountOption'], 'editCountStart' => $formData['editCountOne'], 'editCountEnd' => $formData['editCountTwo'], 'senderId' => $mSender->getID(), 'senderName' => $mSender->getName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; } break; case 'HUB': switch ($mSendModeUsers) { case 'ALL': case 'ACTIVE': case 'GROUP': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; } break; case 'CLUSTER': switch ($mSendModeUsers) { case 'ALL': case 'ACTIVE': case 'GROUP': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; } break; case 'WIKI': switch ($mSendModeUsers) { case 'ALL': case 'ACTIVE': $dbr = wfGetDB(DB_SLAVE, array(), $wgStatsDB); $dbResult = $dbr->select(array('`specials`.`events_local_users`'), array('user_id'), array('wiki_id' => $mWikiId), __METHOD__, array('DISTINCT')); $activeUsers = array(); while ($oMsg = $dbr->FetchObject($dbResult)) { $activeUsers[] = $oMsg->user_id; } if ($dbResult !== false) { $dbr->FreeResult($dbResult); } if (!$DB) { $DB = wfGetDB(DB_MASTER, array(), $wgExternalSharedDB); } $sqlValues = array(); foreach ($activeUsers as $activeUser) { $sqlValues[] = "({$mWikiId}, {$activeUser}, {$result['msgId']}, " . MSG_STATUS_UNSEEN . ')'; } if (count($sqlValues)) { $dbResult = (bool) $DB->Query('INSERT INTO ' . MSG_STATUS_DB . ' (msg_wiki_id, msg_recipient_id, msg_id, msg_status)' . ' VALUES ' . implode(',', $sqlValues) . ';', __METHOD__); $dbInsertResult &= $dbResult; } break; case 'GROUP': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; case 'EDITCOUNT': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'groupName' => $mGroupName, 'editCountOption' => $formData['editCountOption'], 'editCountStart' => $formData['editCountOne'], 'editCountEnd' => $formData['editCountTwo'], 'senderId' => $mSender->getID(), 'senderName' => $mSender->getName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; } break; case 'WIKIS': switch ($mSendModeUsers) { case 'ALL': case 'ACTIVE': case 'GROUP': case 'EDITCOUNT': case 'ANONS': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'wikiNames' => $mWikiNamesArr, 'groupName' => $mGroupName, 'editCountOption' => $formData['editCountOption'], 'editCountStart' => $formData['editCountOne'], 'editCountEnd' => $formData['editCountTwo'], 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; } break; case 'CREATED': switch ($mSendModeUsers) { case 'ALL': case 'ACTIVE': case 'GROUP': case 'EDITCOUNT': case 'ANONS': //add task to TaskManager $oTask = new SWMSendToGroupTask(); $oTask->createTask(array('messageId' => $result['msgId'], 'sendModeWikis' => $mSendModeWikis, 'sendModeUsers' => $mSendModeUsers, 'wikiName' => $mWikiName, 'wikiNames' => $mWikiNamesArr, 'groupName' => $mGroupName, 'wcOption' => $formData['wikiCreationDateOption'], 'wcStartDate' => $formData['wikiCreationDateOne'], 'wcEndDate' => $formData['wikiCreationDateTwo'], 'editCountOption' => $formData['editCountOption'], 'editCountStart' => $formData['editCountOne'], 'editCountEnd' => $formData['editCountTwo'], 'senderId' => $mSender->GetID(), 'senderName' => $mSender->GetName(), 'hubId' => $mHubId, 'clusterId' => $mClusterId), TASK_QUEUED, BatchTask::PRIORITY_HIGH); $result['taskId'] = $oTask->getID(); break; } break; } //end: switch ($mSendModeWikis) } //end: if ($mSendModeUsers == 'USER') } //end: if ($dbResult) => message sent } //end: else =? no errors wfDebug(basename(__FILE__) . ' || ' . __METHOD__ . " || SenderId=" . $mSender->GetID() . ", RecipientId={$mRecipientId}, Expire={$mExpire}, result=" . ($dbInsertResult ? 'true' : 'false') . "\n"); return $result; }
/** * Helper function for readonly errors */ public function dieReadOnly() { $parsed = $this->parseMsg(array('readonlytext')); $this->dieUsage($parsed['info'], $parsed['code'], 0, array('readonlyreason' => wfReadOnlyReason())); }
protected function appendGeneralInfo($property) { global $wgContLang; $data = array(); $mainPage = Title::newMainPage(); $data['mainpage'] = $mainPage->getPrefixedText(); $data['base'] = wfExpandUrl($mainPage->getFullUrl(), PROTO_CURRENT); $data['sitename'] = $GLOBALS['wgSitename']; $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}"; $data['phpversion'] = phpversion(); $data['phpsapi'] = php_sapi_name(); $data['dbtype'] = $GLOBALS['wgDBtype']; $data['dbversion'] = $this->getDB()->getServerVersion(); $svn = SpecialVersion::getSvnRevision($GLOBALS['IP']); if ($svn) { $data['rev'] = $svn; } // 'case-insensitive' option is reserved for future $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive'; if (isset($GLOBALS['wgRightsCode'])) { $data['rightscode'] = $GLOBALS['wgRightsCode']; } $data['rights'] = $GLOBALS['wgRightsText']; $data['lang'] = $GLOBALS['wgLanguageCode']; $fallbacks = array(); foreach ($wgContLang->getFallbackLanguages() as $code) { $fallbacks[] = array('code' => $code); } $data['fallback'] = $fallbacks; $this->getResult()->setIndexedTagName($data['fallback'], 'lang'); if ($wgContLang->isRTL()) { $data['rtl'] = ''; } $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding(); if (wfReadOnly()) { $data['readonly'] = ''; $data['readonlyreason'] = wfReadOnlyReason(); } if ($GLOBALS['wgEnableWriteAPI']) { $data['writeapi'] = ''; } $tz = $GLOBALS['wgLocaltimezone']; $offset = $GLOBALS['wgLocalTZoffset']; if (is_null($tz)) { $tz = 'UTC'; $offset = 0; } elseif (is_null($offset)) { $offset = 0; } $data['timezone'] = $tz; $data['timeoffset'] = intval($offset); $data['articlepath'] = $GLOBALS['wgArticlePath']; $data['scriptpath'] = $GLOBALS['wgScriptPath']; $data['script'] = $GLOBALS['wgScript']; $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath']; $data['server'] = $GLOBALS['wgServer']; $data['wikiid'] = wfWikiID(); $data['time'] = wfTimestamp(TS_ISO_8601, time()); if ($GLOBALS['wgMiserMode']) { $data['misermode'] = ''; } wfRunHooks('APIQuerySiteInfoGeneralInfo', array($this, &$data)); return $this->getResult()->addValue('query', $property, $data); }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param array $limit Set of restriction keys * @param array $expiry Per restriction type expiration * @param int &$cascade Set to false if cascading protection isn't allowed. * @param string $reason * @param User $user The user updating the restrictions * @param string|string[] $tags Change tags to add to the pages and protection log entries * ($user should be able to add the specified tags before this is called) * @return Status Status object; if action is taken, $status->value is the log_id of the * protection log entry. */ public function doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user, $tags = null) { global $wgCascadingRestrictionLevels, $wgContLang; if (wfReadOnly()) { return Status::newFatal('readonlytext', wfReadOnlyReason()); } $this->loadPageData('fromdbmaster'); $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->getId(); if (!$cascade) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); // @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); // we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB(DB_MASTER); foreach ($restrictionTypes as $action) { if (!isset($expiry[$action]) || $expiry[$action] === $dbw->getInfinity()) { $expiry[$action] = 'infinity'; } if (!isset($limit[$action])) { $limit[$action] = ''; } elseif ($limit[$action] != '') { $protect = true; } // Get current restrictions on $action $current = implode('', $this->mTitle->getRestrictions($action)); if ($current != '') { $isProtected = true; } if ($limit[$action] != $current) { $changed = true; } elseif ($limit[$action] != '') { // Only check expiry change if the action is actually being // protected, since expiry does nothing on an not-protected // action. if ($this->mTitle->getRestrictionExpiry($action) != $expiry[$action]) { $changed = true; } } } if (!$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade) { $changed = true; } // If nothing has changed, do nothing if (!$changed) { return Status::newGood(); } if (!$protect) { // No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ($isProtected) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } // Truncate for whole multibyte characters $reason = $wgContLang->truncate($reason, 255); $logRelationsValues = []; $logRelationsField = null; $logParamsDetails = []; // Null revision (used for change tag insertion) $nullRevision = null; if ($id) { // Protection of existing page if (!Hooks::run('ArticleProtect', [&$this, &$user, $limit, $reason])) { return Status::newGood(); } // Only certain restrictions can cascade... $editrestriction = isset($limit['edit']) ? [$limit['edit']] : $this->mTitle->getRestrictions('edit'); foreach (array_keys($editrestriction, 'sysop') as $key) { $editrestriction[$key] = 'editprotected'; // backwards compatibility } foreach (array_keys($editrestriction, 'autoconfirmed') as $key) { $editrestriction[$key] = 'editsemiprotected'; // backwards compatibility } $cascadingRestrictionLevels = $wgCascadingRestrictionLevels; foreach (array_keys($cascadingRestrictionLevels, 'sysop') as $key) { $cascadingRestrictionLevels[$key] = 'editprotected'; // backwards compatibility } foreach (array_keys($cascadingRestrictionLevels, 'autoconfirmed') as $key) { $cascadingRestrictionLevels[$key] = 'editsemiprotected'; // backwards compatibility } // The schema allows multiple restrictions if (!array_intersect($editrestriction, $cascadingRestrictionLevels)) { $cascade = false; } // insert null revision to identify the page protection change as edit summary $latest = $this->getLatest(); $nullRevision = $this->insertProtectNullRevision($revCommentMsg, $limit, $expiry, $cascade, $reason, $user); if ($nullRevision === null) { return Status::newFatal('no-null-revision', $this->mTitle->getPrefixedText()); } $logRelationsField = 'pr_id'; // Update restrictions table foreach ($limit as $action => $restrictions) { $dbw->delete('page_restrictions', ['pr_page' => $id, 'pr_type' => $action], __METHOD__); if ($restrictions != '') { $cascadeValue = $cascade && $action == 'edit' ? 1 : 0; $dbw->insert('page_restrictions', ['pr_id' => $dbw->nextSequenceValue('page_restrictions_pr_id_seq'), 'pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascadeValue, 'pr_expiry' => $dbw->encodeExpiry($expiry[$action])], __METHOD__); $logRelationsValues[] = $dbw->insertId(); $logParamsDetails[] = ['type' => $action, 'level' => $restrictions, 'expiry' => $expiry[$action], 'cascade' => (bool) $cascadeValue]; } } // Clear out legacy restriction fields $dbw->update('page', ['page_restrictions' => ''], ['page_id' => $id], __METHOD__); Hooks::run('NewRevisionFromEditComplete', [$this, $nullRevision, $latest, $user]); Hooks::run('ArticleProtectComplete', [&$this, &$user, $limit, $reason]); } else { // Protection of non-existing page (also known as "title protection") // Cascade protection is meaningless in this case $cascade = false; if ($limit['create'] != '') { $dbw->replace('protected_titles', [['pt_namespace', 'pt_title']], ['pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->timestamp(), 'pt_expiry' => $dbw->encodeExpiry($expiry['create']), 'pt_user' => $user->getId(), 'pt_reason' => $reason], __METHOD__); $logParamsDetails[] = ['type' => 'create', 'level' => $limit['create'], 'expiry' => $expiry['create']]; } else { $dbw->delete('protected_titles', ['pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey()], __METHOD__); } } $this->mTitle->flushRestrictions(); InfoAction::invalidateCache($this->mTitle); if ($logAction == 'unprotect') { $params = []; } else { $protectDescriptionLog = $this->protectDescriptionLog($limit, $expiry); $params = ['4::description' => $protectDescriptionLog, '5:bool:cascade' => $cascade, 'details' => $logParamsDetails]; } // Update the protection log $logEntry = new ManualLogEntry('protect', $logAction); $logEntry->setTarget($this->mTitle); $logEntry->setComment($reason); $logEntry->setPerformer($user); $logEntry->setParameters($params); if (!is_null($nullRevision)) { $logEntry->setAssociatedRevId($nullRevision->getId()); } $logEntry->setTags($tags); if ($logRelationsField !== null && count($logRelationsValues)) { $logEntry->setRelations([$logRelationsField => $logRelationsValues]); } $logId = $logEntry->insert(); $logEntry->publish($logId); return Status::newGood($logId); }
/** * Replace entire showEditForm, need to add our own textbox and stuff */ function showEditForm($formCallback = null) { global $wgOut, $wgUser, $wgLang, $wgContLang, $wgMaxArticleSize, $wgTitle, $wgRequest; # If $wgTitle is null, that means we're in API mode. # Some hook probably called this function without checking # for is_null($wgTitle) first. Bail out right here so we don't # do lots of work just to discard it right after. if (is_null($wgTitle)) { return; } $fname = 'EditPage::showEditForm'; wfProfileIn($fname); $sk = $wgUser->getSkin(); wfRunHooks('EditPage::showEditForm:initial', array(&$this)); #need to parse the preview early so that we know which templates are used, #otherwise users with "show preview after edit box" will get a blank list #we parse this near the beginning so that setHeaders can do the title #setting work instead of leaving it in getPreviewText $previewOutput = ''; if ($this->formtype == 'preview') { $previewOutput = $this->getPreviewText(); } $this->setHeaders(); # Enabled article-related sidebar, toplinks, etc. $wgOut->setArticleRelated(true); if ($this->isConflict) { $wgOut->wrapWikiMsg("<div class='mw-explainconflict'>\n\$1</div>", 'explainconflict'); $this->textbox2 = $this->textbox1; $this->textbox1 = $this->getContent(); $this->edittime = $this->mArticle->getTimestamp(); # MeanEditor: too complicated for visual editing $this->noVisualEditor = false; } else { if ($this->section != '' && $this->section != 'new') { $matches = array(); if (!$this->summary && !$this->preview && !$this->diff) { preg_match("/^(=+)(.+)\\1/mi", $this->textbox1, $matches); if (!empty($matches[2])) { global $wgParser; $this->summary = "/* " . $wgParser->stripSectionName(trim($matches[2])) . " */ "; } } } if ($this->missingComment) { $wgOut->wrapWikiMsg('<div id="mw-missingcommenttext">$1</div>', 'missingcommenttext'); } if ($this->missingSummary && $this->section != 'new') { $wgOut->wrapWikiMsg('<div id="mw-missingsummary">$1</div>', 'missingsummary'); } if ($this->missingSummary && $this->section == 'new') { $wgOut->wrapWikiMsg('<div id="mw-missingcommentheader">$1</div>', 'missingcommentheader'); } if ($this->hookError !== '') { $wgOut->addWikiText($this->hookError); } if (!$this->checkUnicodeCompliantBrowser()) { $wgOut->addWikiMsg('nonunicodebrowser'); } if (isset($this->mArticle) && isset($this->mArticle->mRevision)) { // Let sysop know that this will make private content public if saved if (!$this->mArticle->mRevision->userCan(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1</div>\n", 'rev-deleted-text-permission'); } else { if ($this->mArticle->mRevision->isDeleted(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1</div>\n", 'rev-deleted-text-view'); } } if (!$this->mArticle->mRevision->isCurrent()) { $this->mArticle->setOldSubtitle($this->mArticle->mRevision->getId()); $wgOut->addWikiMsg('editingold'); } } } if (wfReadOnly()) { $wgOut->wrapWikiMsg("<div id=\"mw-read-only-warning\">\n\$1\n</div>", array('readonlywarning', wfReadOnlyReason())); # MeanEditor: visual editing makes no sense here $this->noVisualEditor = true; } elseif ($wgUser->isAnon() && $this->formtype != 'preview') { $wgOut->wrapWikiMsg('<div id="mw-anon-edit-warning">$1</div>', 'anoneditwarning'); } else { if ($this->isCssJsSubpage) { # Check the skin exists if ($this->isValidCssJsSubpage) { if ($this->formtype !== 'preview') { $wgOut->addWikiMsg('usercssjsyoucanpreview'); } } else { $wgOut->addWikiMsg('userinvalidcssjstitle', $wgTitle->getSkinFromCssJsSubpage()); } } } $classes = array(); // Textarea CSS if ($this->mTitle->getNamespace() == NS_MEDIAWIKI) { } elseif ($this->mTitle->isProtected('edit')) { # Is the title semi-protected? if ($this->mTitle->isSemiProtected()) { $noticeMsg = 'semiprotectedpagewarning'; $classes[] = 'mw-textarea-sprotected'; } else { # Then it must be protected based on static groups (regular) $noticeMsg = 'protectedpagewarning'; $classes[] = 'mw-textarea-protected'; } $wgOut->addHTML("<div class='mw-warning-with-logexcerpt'>\n"); $wgOut->addWikiMsg($noticeMsg); LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle->getPrefixedText(), '', 1); $wgOut->addHTML("</div>\n"); } if ($this->mTitle->isCascadeProtected()) { # Is this page under cascading protection from some source pages? list($cascadeSources, ) = $this->mTitle->getCascadeProtectionSources(); $notice = "<div class='mw-cascadeprotectedwarning'>\$1\n"; $cascadeSourcesCount = count($cascadeSources); if ($cascadeSourcesCount > 0) { # Explain, and list the titles responsible foreach ($cascadeSources as $page) { $notice .= '* [[:' . $page->getPrefixedText() . "]]\n"; } } $notice .= '</div>'; $wgOut->wrapWikiMsg($notice, array('cascadeprotectedwarning', $cascadeSourcesCount)); } if (!$this->mTitle->exists() && $this->mTitle->getRestrictions('create')) { $wgOut->wrapWikiMsg('<div class="mw-titleprotectedwarning">$1</div>', 'titleprotectedwarning'); } if ($this->kblength === false) { # MeanEditor: the length will probably be different in HTML $this->kblength = (int) (strlen($this->textbox1) / 1024); } if ($this->tooBig || $this->kblength > $wgMaxArticleSize) { $wgOut->addHTML("<div class='error' id='mw-edit-longpageerror'>\n"); $wgOut->addWikiMsg('longpageerror', $wgLang->formatNum($this->kblength), $wgLang->formatNum($wgMaxArticleSize)); $wgOut->addHTML("</div>\n"); } elseif ($this->kblength > 29) { $wgOut->addHTML("<div id='mw-edit-longpagewarning'>\n"); $wgOut->addWikiMsg('longpagewarning', $wgLang->formatNum($this->kblength)); $wgOut->addHTML("</div>\n"); } $q = 'action=' . $this->action; #if ( "no" == $redirect ) { $q .= "&redirect=no"; } $action = $wgTitle->escapeLocalURL($q); $summary = wfMsg('summary'); $subject = wfMsg('subject'); $cancel = $sk->makeKnownLink($wgTitle->getPrefixedText(), wfMsgExt('cancel', array('parseinline'))); $separator = wfMsgExt('pipe-separator', 'escapenoentities'); $edithelpurl = Skin::makeInternalOrExternalUrl(wfMsgForContent('edithelppage')); $edithelp = '<a target="helpwindow" href="' . $edithelpurl . '">' . htmlspecialchars(wfMsg('edithelp')) . '</a> ' . htmlspecialchars(wfMsg('newwindow')); global $wgRightsText; if ($wgRightsText) { $copywarnMsg = array('copyrightwarning', '[[' . wfMsgForContent('copyrightpage') . ']]', $wgRightsText); } else { $copywarnMsg = array('copyrightwarning2', '[[' . wfMsgForContent('copyrightpage') . ']]'); } /* MeanEditor: always disable the toolbar */ if ($wgUser->getOption('showtoolbar') and !$this->isCssJsSubpage) { # prepare toolbar for edit buttons $toolbar = ''; } else { $toolbar = ''; } // activate checkboxes if user wants them to be always active if (!$this->preview && !$this->diff) { # Sort out the "watch" checkbox if ($wgUser->getOption('watchdefault')) { # Watch all edits $this->watchthis = true; } elseif ($wgUser->getOption('watchcreations') && !$this->mTitle->exists()) { # Watch creations $this->watchthis = true; } elseif ($this->mTitle->userIsWatching()) { # Already watched $this->watchthis = true; } # May be overriden by request parameters if ($wgRequest->getBool('watchthis')) { $this->watchthis = true; } if ($wgUser->getOption('minordefault')) { $this->minoredit = true; } # MeanEditor: User preference if ($wgUser->getOption('prefer_traditional_editor')) { $this->userWantsTraditionalEditor = true; } } $wgOut->addHTML($this->editFormPageTop); if ($wgUser->getOption('previewontop')) { $this->displayPreviewArea($previewOutput, true); } $wgOut->addHTML($this->editFormTextTop); # if this is a comment, show a subject line at the top, which is also the edit summary. # Otherwise, show a summary field at the bottom $summarytext = $wgContLang->recodeForEdit($this->summary); # If a blank edit summary was previously provided, and the appropriate # user preference is active, pass a hidden tag as wpIgnoreBlankSummary. This will stop the # user being bounced back more than once in the event that a summary # is not required. ##### # For a bit more sophisticated detection of blank summaries, hash the # automatic one and pass that in the hidden field wpAutoSummary. $summaryhiddens = ''; if ($this->missingSummary) { $summaryhiddens .= Xml::hidden('wpIgnoreBlankSummary', true); } $autosumm = $this->autoSumm ? $this->autoSumm : md5($this->summary); $summaryhiddens .= Xml::hidden('wpAutoSummary', $autosumm); if ($this->section == 'new') { $commentsubject = ''; if (!$wgRequest->getBool('nosummary')) { # Add a class if 'missingsummary' is triggered to allow styling of the summary line $summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary'; $commentsubject = Xml::tags('label', array('for' => 'wpSummary'), $subject); $commentsubject = Xml::tags('span', array('class' => $summaryClass, 'id' => "wpSummaryLabel"), $commentsubject); $commentsubject .= ' '; $commentsubject .= Xml::input('wpSummary', 60, $summarytext, array('id' => 'wpSummary', 'maxlength' => '200', 'tabindex' => '1')); } $editsummary = "<div class='editOptions'>\n"; global $wgParser; $formattedSummary = wfMsgForContent('newsectionsummary', $wgParser->stripSectionName($this->summary)); $subjectpreview = $summarytext && $this->preview ? "<div class=\"mw-summary-preview\">" . wfMsg('subject-preview') . $sk->commentBlock($formattedSummary, $this->mTitle, true) . "</div>\n" : ''; $summarypreview = ''; } else { $commentsubject = ''; # Add a class if 'missingsummary' is triggered to allow styling of the summary line $summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary'; $editsummary = Xml::tags('label', array('for' => 'wpSummary'), $summary); $editsummary = Xml::tags('span', array('class' => $summaryClass, 'id' => "wpSummaryLabel"), $editsummary) . ' '; $editsummary .= Xml::input('wpSummary', 60, $summarytext, array('id' => 'wpSummary', 'maxlength' => '200', 'tabindex' => '1')); // No idea where this is closed. $editsummary = Xml::openElement('div', array('class' => 'editOptions')) . $editsummary . '<br/>'; $summarypreview = ''; if ($summarytext && $this->preview) { $summarypreview = Xml::tags('div', array('class' => 'mw-summary-preview'), wfMsg('summary-preview') . $sk->commentBlock($this->summary, $this->mTitle)); } $subjectpreview = ''; } $commentsubject .= $summaryhiddens; # Set focus to the edit box on load, except on preview or diff, where it would interfere with the display if (!$this->preview && !$this->diff) { $wgOut->setOnloadHandler('document.editform.wpTextbox1.focus()'); } $templates = $this->getTemplates(); $formattedtemplates = $sk->formatTemplates($templates, $this->preview, $this->section != ''); $hiddencats = $this->mArticle->getHiddenCategories(); $formattedhiddencats = $sk->formatHiddenCategories($hiddencats); global $wgUseMetadataEdit; if ($wgUseMetadataEdit) { $metadata = $this->mMetaData; $metadata = htmlspecialchars($wgContLang->recodeForEdit($metadata)); $top = wfMsgWikiHtml('metadata_help'); /* ToDo: Replace with clean code */ $ew = $wgUser->getOption('editwidth'); if ($ew) { $ew = " style=\"width:100%\""; } else { $ew = ''; } $cols = $wgUser->getIntOption('cols'); /* /ToDo */ $metadata = $top . "<textarea name='metadata' rows='3' cols='{$cols}'{$ew}>{$metadata}</textarea>"; } else { $metadata = ""; } $recreate = ''; if ($this->wasDeletedSinceLastEdit()) { if ('save' != $this->formtype) { $wgOut->wrapWikiMsg("<div class='error mw-deleted-while-editing'>\n\$1</div>", 'deletedwhileediting'); } else { // Hide the toolbar and edit area, user can click preview to get it back // Add an confirmation checkbox and explanation. $toolbar = ''; $recreate = '<div class="mw-confirm-recreate">' . $wgOut->parse(wfMsg('confirmrecreate', $this->lastDelete->user_name, $this->lastDelete->log_comment)) . Xml::checkLabel(wfMsg('recreate'), 'wpRecreate', 'wpRecreate', false, array('title' => $sk->titleAttrib('recreate'), 'tabindex' => 1, 'id' => 'wpRecreate')) . '</div>'; } } $tabindex = 2; $checkboxes = $this->getCheckboxes($tabindex, $sk, array('minor' => $this->minoredit, 'watch' => $this->watchthis, 'want_traditional_editor' => $this->userWantsTraditionalEditor)); $checkboxhtml = implode($checkboxes, "\n"); $buttons = $this->getEditButtons($tabindex); $buttonshtml = implode($buttons, "\n"); $safemodehtml = $this->checkUnicodeCompliantBrowser() ? '' : Xml::hidden('safemode', '1'); $wgOut->addHTML(<<<END {$toolbar} <form id="editform" name="editform" method="post" action="{$action}" enctype="multipart/form-data"> END ); if (is_callable($formCallback)) { call_user_func_array($formCallback, array(&$wgOut)); } wfRunHooks('EditPage::showEditForm:fields', array(&$this, &$wgOut)); // Put these up at the top to ensure they aren't lost on early form submission $this->showFormBeforeText(); $wgOut->addHTML(<<<END {$recreate} {$commentsubject} {$subjectpreview} {$this->editFormTextBeforeContent} END ); if ($this->isConflict || $this->diff) { # MeanEditor: should be redundant, but let's be sure $this->noVisualEditor = true; } # MeanEditor: also apply htmlspecialchars? See $encodedtext $html_text = $this->safeUnicodeOutput($this->textbox1); if (!($this->noVisualEditor || $this->userWantsTraditionalEditor)) { $this->noVisualEditor = wfRunHooks('EditPage::wiki2html', array($this->mArticle, $wgUser, &$this, &$html_text)); } if (!$this->noVisualEditor && !$this->userWantsTraditionalEditor) { $this->noVisualEditor = wfRunHooks('EditPage::showBox', array(&$this, $html_text, $rows, $cols, $ew)); } if (!$this->noVisualEditor && !$this->userWantsTraditionalEditor) { $wgOut->addHTML("<input type='hidden' value=\"0\" name=\"wpNoVisualEditor\" />\n"); } else { $wgOut->addHTML("<input type='hidden' value=\"1\" name=\"wpNoVisualEditor\" />\n"); $this->showTextbox1($classes); } $wgOut->wrapWikiMsg("<div id=\"editpage-copywarn\">\n\$1\n</div>", $copywarnMsg); $wgOut->addHTML(<<<END {$this->editFormTextAfterWarn} {$metadata} {$editsummary} {$summarypreview} {$checkboxhtml} {$safemodehtml} END ); $wgOut->addHTML("<div class='editButtons'>\n{$buttonshtml}\n\t<span class='editHelp'>{$cancel}{$separator}{$edithelp}</span>\n</div><!-- editButtons -->\n</div><!-- editOptions -->"); /** * To make it harder for someone to slip a user a page * which submits an edit form to the wiki without their * knowledge, a random token is associated with the login * session. If it's not passed back with the submission, * we won't save the page, or render user JavaScript and * CSS previews. * * For anon editors, who may not have a session, we just * include the constant suffix to prevent editing from * broken text-mangling proxies. */ $token = htmlspecialchars($wgUser->editToken()); $wgOut->addHTML("\n<input type='hidden' value=\"{$token}\" name=\"wpEditToken\" />\n"); $this->showEditTools(); $wgOut->addHTML(<<<END {$this->editFormTextAfterTools} <div class='templatesUsed'> {$formattedtemplates} </div> <div class='hiddencats'> {$formattedhiddencats} </div> END ); if ($this->isConflict && wfRunHooks('EditPageBeforeConflictDiff', array(&$this, &$wgOut))) { $wgOut->wrapWikiMsg('==$1==', "yourdiff"); $de = new DifferenceEngine($this->mTitle); $de->setText($this->textbox2, $this->textbox1); $de->showDiff(wfMsg("yourtext"), wfMsg("storedversion")); $wgOut->wrapWikiMsg('==$1==', "yourtext"); $this->showTextbox2(); } $wgOut->addHTML($this->editFormTextBottom); $wgOut->addHTML("</form>\n"); if (!$wgUser->getOption('previewontop')) { $this->displayPreviewArea($previewOutput, false); } wfProfileOut($fname); }
protected function showHeader() { global $wgOut, $wgUser, $wgMaxArticleSize, $wgLang; if ($this->mTitle->isTalkPage()) { $wgOut->addWikiMsg('talkpagetext'); } # Optional notices on a per-namespace and per-page basis $editnotice_ns = 'editnotice-' . $this->mTitle->getNamespace(); $editnotice_ns_message = wfMessage($editnotice_ns)->inContentLanguage(); if ($editnotice_ns_message->exists()) { $wgOut->addWikiText($editnotice_ns_message->plain()); } if (MWNamespace::hasSubpages($this->mTitle->getNamespace())) { $parts = explode('/', $this->mTitle->getDBkey()); $editnotice_base = $editnotice_ns; while (count($parts) > 0) { $editnotice_base .= '-' . array_shift($parts); $editnotice_base_msg = wfMessage($editnotice_base)->inContentLanguage(); if ($editnotice_base_msg->exists()) { $wgOut->addWikiText($editnotice_base_msg->plain()); } } } else { # Even if there are no subpages in namespace, we still don't want / in MW ns. $editnoticeText = $editnotice_ns . '-' . str_replace('/', '-', $this->mTitle->getDBkey()); $editnoticeMsg = wfMessage($editnoticeText)->inContentLanguage(); if ($editnoticeMsg->exists()) { $wgOut->addWikiText($editnoticeMsg->plain()); } } if ($this->isConflict) { $wgOut->wrapWikiMsg("<div class='mw-explainconflict'>\n\$1\n</div>", 'explainconflict'); $this->edittime = $this->mArticle->getTimestamp(); } else { if ($this->section != '' && !$this->isSectionEditSupported()) { // We use $this->section to much before this and getVal('wgSection') directly in other places // at this point we can't reset $this->section to '' to fallback to non-section editing. // Someone is welcome to try refactoring though $wgOut->showErrorPage('sectioneditnotsupported-title', 'sectioneditnotsupported-text'); return false; } if ($this->section != '' && $this->section != 'new') { if (!$this->summary && !$this->preview && !$this->diff) { $sectionTitle = self::extractSectionTitle($this->textbox1); if ($sectionTitle !== false) { $this->summary = "/* {$sectionTitle} */ "; } } } if ($this->missingComment) { $wgOut->wrapWikiMsg("<div id='mw-missingcommenttext'>\n\$1\n</div>", 'missingcommenttext'); } if ($this->missingSummary && $this->section != 'new') { $wgOut->wrapWikiMsg("<div id='mw-missingsummary'>\n\$1\n</div>", 'missingsummary'); } if ($this->missingSummary && $this->section == 'new') { $wgOut->wrapWikiMsg("<div id='mw-missingcommentheader'>\n\$1\n</div>", 'missingcommentheader'); } if ($this->hookError !== '') { $wgOut->addWikiText($this->hookError); } if (!$this->checkUnicodeCompliantBrowser()) { $wgOut->addWikiMsg('nonunicodebrowser'); } if ($this->section != 'new') { $revision = $this->mArticle->getRevisionFetched(); if ($revision) { // Let sysop know that this will make private content public if saved if (!$revision->userCan(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1\n</div>\n", 'rev-deleted-text-permission'); } elseif ($revision->isDeleted(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1\n</div>\n", 'rev-deleted-text-view'); } if (!$revision->isCurrent()) { $this->mArticle->setOldSubtitle($revision->getId()); $wgOut->addWikiMsg('editingold'); } } elseif ($this->mTitle->exists()) { // Something went wrong $wgOut->wrapWikiMsg("<div class='errorbox'>\n\$1\n</div>\n", array('missing-article', $this->mTitle->getPrefixedText(), wfMsgNoTrans('missingarticle-rev', $this->oldid))); } } } if (wfReadOnly()) { $wgOut->wrapWikiMsg("<div id=\"mw-read-only-warning\">\n\$1\n</div>", array('readonlywarning', wfReadOnlyReason())); } elseif ($wgUser->isAnon()) { if ($this->formtype != 'preview') { $wgOut->wrapWikiMsg("<div id=\"mw-anon-edit-warning\">\n\$1</div>", 'anoneditwarning'); } else { $wgOut->wrapWikiMsg("<div id=\"mw-anon-preview-warning\">\n\$1</div>", 'anonpreviewwarning'); } } else { if ($this->isCssJsSubpage) { # Check the skin exists if ($this->isWrongCaseCssJsPage) { $wgOut->wrapWikiMsg("<div class='error' id='mw-userinvalidcssjstitle'>\n\$1\n</div>", array('userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage())); } if ($this->getTitle()->isSubpageOf($wgUser->getUserPage())) { if ($this->formtype !== 'preview') { if ($this->isCssSubpage) { $wgOut->wrapWikiMsg("<div id='mw-usercssyoucanpreview'>\n\$1\n</div>", array('usercssyoucanpreview')); } if ($this->isJsSubpage) { $wgOut->wrapWikiMsg("<div id='mw-userjsyoucanpreview'>\n\$1\n</div>", array('userjsyoucanpreview')); } } } } } if ($this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected('edit')) { # Is the title semi-protected? if ($this->mTitle->isSemiProtected()) { $noticeMsg = 'semiprotectedpagewarning'; } else { # Then it must be protected based on static groups (regular) $noticeMsg = 'protectedpagewarning'; } LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle, '', array('lim' => 1, 'msgKey' => array($noticeMsg))); } if ($this->mTitle->isCascadeProtected()) { # Is this page under cascading protection from some source pages? list($cascadeSources, ) = $this->mTitle->getCascadeProtectionSources(); $notice = "<div class='mw-cascadeprotectedwarning'>\n\$1\n"; $cascadeSourcesCount = count($cascadeSources); if ($cascadeSourcesCount > 0) { # Explain, and list the titles responsible foreach ($cascadeSources as $page) { $notice .= '* [[:' . $page->getPrefixedText() . "]]\n"; } } $notice .= '</div>'; $wgOut->wrapWikiMsg($notice, array('cascadeprotectedwarning', $cascadeSourcesCount)); } if (!$this->mTitle->exists() && $this->mTitle->getRestrictions('create')) { LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle, '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('titleprotectedwarning'), 'wrap' => "<div class=\"mw-titleprotectedwarning\">\n\$1</div>")); } if ($this->kblength === false) { $this->kblength = (int) (strlen($this->textbox1) / 1024); } if ($this->tooBig || $this->kblength > $wgMaxArticleSize) { $wgOut->wrapWikiMsg("<div class='error' id='mw-edit-longpageerror'>\n\$1\n</div>", array('longpageerror', $wgLang->formatNum($this->kblength), $wgLang->formatNum($wgMaxArticleSize))); } else { if (!wfMessage('longpage-hint')->isDisabled()) { $wgOut->wrapWikiMsg("<div id='mw-edit-longpage-hint'>\n\$1\n</div>", array('longpage-hint', $wgLang->formatSize(strlen($this->textbox1)), strlen($this->textbox1))); } } }
/** * Translates an EditPage error code into a corresponding message ID * @param $error The error code * @return String */ public static function processEditErrors($error) { switch ($error) { case EditPage::AS_SUCCESS_NEW_ARTICLE: case EditPage::AS_SUCCESS_UPDATE: return null; case EditPage::AS_SPAM_ERROR: return 'spamprotectiontext'; case EditPage::AS_BLOCKED_PAGE_FOR_USER: return 'blockedtitle'; case EditPage::AS_IMAGE_REDIRECT_ANON: return 'uploadnologin'; case EditPage::AS_READ_ONLY_PAGE_ANON: return 'loginreqtitle'; case EditPage::AS_READ_ONLY_PAGE_LOGGED: case EditPage::AS_READ_ONLY_PAGE: return array('readonlytext', array(wfReadOnlyReason())); case EditPage::AS_RATE_LIMITED: return 'actionthrottledtext'; case EditPage::AS_NO_CREATE_PERMISSION: return 'nocreatetext'; case EditPage::AS_BLANK_ARTICLE: return 'autoedit-blankpage'; case EditPage::AS_IMAGE_REDIRECT_LOGGED: return 'badaccess'; case EditPage::AS_HOOK_ERROR_EXPECTED: case EditPage::AS_HOOK_ERROR: return 'sf_formedit_hookerror'; case EditPage::AS_CONFLICT_DETECTED: return 'editconflict'; case EditPage::AS_CONTENT_TOO_BIG: case EditPage::AS_ARTICLE_WAS_DELETED: case EditPage::AS_SUMMARY_NEEDED: case EditPage::AS_TEXTBOX_EMPTY: case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_END: case EditPage::AS_FILTERING: default: return array('internalerror_text', array($error)); } }
protected function showHeader() { global $wgOut, $wgUser, $wgMaxArticleSize, $wgLang; if ($this->isConflict) { $wgOut->wrapWikiMsg("<div class='mw-explainconflict'>\n\$1\n</div>", 'explainconflict'); $this->edittime = $this->mArticle->getTimestamp(); } else { if ($this->section != '' && !$this->isSectionEditSupported()) { // We use $this->section to much before this and getVal('wgSection') directly in other places // at this point we can't reset $this->section to '' to fallback to non-section editing. // Someone is welcome to try refactoring though $wgOut->showErrorPage('sectioneditnotsupported-title', 'sectioneditnotsupported-text'); return false; } if ($this->section != '' && $this->section != 'new') { $matches = array(); if (!$this->summary && !$this->preview && !$this->diff) { preg_match("/^(=+)(.+)\\1/mi", $this->textbox1, $matches); if (!empty($matches[2])) { global $wgParser; $this->summary = "/* " . $wgParser->stripSectionName(trim($matches[2])) . " */ "; } } } if ($this->missingComment) { $wgOut->wrapWikiMsg("<div id='mw-missingcommenttext'>\n\$1\n</div>", 'missingcommenttext'); } if ($this->missingSummary && $this->section != 'new') { $wgOut->wrapWikiMsg("<div id='mw-missingsummary'>\n\$1\n</div>", 'missingsummary'); } if ($this->missingSummary && $this->section == 'new') { $wgOut->wrapWikiMsg("<div id='mw-missingcommentheader'>\n\$1\n</div>", 'missingcommentheader'); } if ($this->hookError !== '') { $wgOut->addWikiText($this->hookError); } if (!$this->checkUnicodeCompliantBrowser()) { $wgOut->addWikiMsg('nonunicodebrowser'); } if (isset($this->mArticle) && isset($this->mArticle->mRevision)) { // Let sysop know that this will make private content public if saved if (!$this->mArticle->mRevision->userCan(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1\n</div>\n", 'rev-deleted-text-permission'); } elseif ($this->mArticle->mRevision->isDeleted(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1\n</div>\n", 'rev-deleted-text-view'); } if (!$this->mArticle->mRevision->isCurrent()) { $this->mArticle->setOldSubtitle($this->mArticle->mRevision->getId()); $wgOut->addWikiMsg('editingold'); } } } if (wfReadOnly()) { $wgOut->wrapWikiMsg("<div id=\"mw-read-only-warning\">\n\$1\n</div>", array('readonlywarning', wfReadOnlyReason())); } elseif ($wgUser->isAnon()) { if ($this->formtype != 'preview') { $wgOut->wrapWikiMsg("<div id=\"mw-anon-edit-warning\">\n\$1</div>", 'anoneditwarning'); } else { $wgOut->wrapWikiMsg("<div id=\"mw-anon-preview-warning\">\n\$1</div>", 'anonpreviewwarning'); } } else { if ($this->isCssJsSubpage) { # Check the skin exists if ($this->isWrongCaseCssJsPage) { $wgOut->wrapWikiMsg("<div class='error' id='mw-userinvalidcssjstitle'>\n\$1\n</div>", array('userinvalidcssjstitle', $this->getContextTitle()->getSkinFromCssJsSubpage())); } if ($this->formtype !== 'preview') { if ($this->isCssSubpage) { $wgOut->wrapWikiMsg("<div id='mw-usercssyoucanpreview'>\n\$1\n</div>", array('usercssyoucanpreview')); } if ($this->isJsSubpage) { $wgOut->wrapWikiMsg("<div id='mw-userjsyoucanpreview'>\n\$1\n</div>", array('userjsyoucanpreview')); } } } } if ($this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected('edit')) { # Is the title semi-protected? if ($this->mTitle->isSemiProtected()) { $noticeMsg = 'semiprotectedpagewarning'; } else { # Then it must be protected based on static groups (regular) $noticeMsg = 'protectedpagewarning'; } LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle->getPrefixedText(), '', array('lim' => 1, 'msgKey' => array($noticeMsg))); } if ($this->mTitle->isCascadeProtected()) { # Is this page under cascading protection from some source pages? list($cascadeSources, ) = $this->mTitle->getCascadeProtectionSources(); $notice = "<div class='mw-cascadeprotectedwarning'>\n\$1\n"; $cascadeSourcesCount = count($cascadeSources); if ($cascadeSourcesCount > 0) { # Explain, and list the titles responsible foreach ($cascadeSources as $page) { $notice .= '* [[:' . $page->getPrefixedText() . "]]\n"; } } $notice .= '</div>'; $wgOut->wrapWikiMsg($notice, array('cascadeprotectedwarning', $cascadeSourcesCount)); } if (!$this->mTitle->exists() && $this->mTitle->getRestrictions('create')) { LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle->getPrefixedText(), '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('titleprotectedwarning'), 'wrap' => "<div class=\"mw-titleprotectedwarning\">\n\$1</div>")); } if ($this->kblength === false) { $this->kblength = (int) (strlen($this->textbox1) / 1024); } if ($this->tooBig || $this->kblength > $wgMaxArticleSize) { $wgOut->wrapWikiMsg("<div class='error' id='mw-edit-longpageerror'>\n\$1\n</div>", array('longpageerror', $wgLang->formatNum($this->kblength), $wgLang->formatNum($wgMaxArticleSize))); } else { if (!wfMessage('longpage-hint')->isDisabled()) { $wgOut->wrapWikiMsg("<div id='mw-edit-longpage-hint'>\n\$1\n</div>", array('longpage-hint', $wgLang->formatSize(strlen($this->textbox1)), strlen($this->textbox1))); } } }
/** * Depending on the requested action this method will try to store/preview * the data in mOptions or retrieve the edit form. * * The form and target page will be available in mOptions after execution of * the method. * * Errors and warnings are logged in the API result under the 'errors' key. * The general request status is maintained in mStatus. * * @global $wgRequest * @global $wgOut * @global SFFormPrinter $sfgFormPrinter * @throws MWException */ public function doAction() { global $wgOut, $wgParser, $wgRequest, $sfgFormPrinter; // if the wiki is read-only, do not save if (wfReadOnly()) { if ($this->mAction === self::ACTION_SAVE) { throw new MWException(wfMessage('sf_autoedit_readonly', wfReadOnlyReason())->parse()); } // even if not saving notify client anyway. Might want to dislay a notice $this->logMessage(wfMessage('sf_autoedit_readonly', wfReadOnlyReason())->parse(), self::NOTICE); } // find the title of the form to be used $formTitle = $this->getFormTitle(); // get the form content $formContent = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $this->getTextForPage($formTitle)); // signals that the form was submitted // always true, else we would not be here $isFormSubmitted = $this->mAction === self::ACTION_SAVE || $this->mAction === self::ACTION_PREVIEW || $this->mAction === self::ACTION_DIFF; // the article id of the form to be used $formArticleId = $formTitle->getArticleID(); // the name of the target page; might be empty when using the one-step-process $targetName = $this->mOptions['target']; // if the target page was not specified, try finding the page name formula // (Why is this not done in SFFormPrinter::formHTML?) if ($targetName === '') { // Parse the form to see if it has a 'page name' value set. if (preg_match('/{{{\\s*info.*page name\\s*=\\s*(.*)}}}/msU', $formContent, $matches)) { $pageNameElements = SFUtils::getFormTagComponents(trim($matches[1])); $targetNameFormula = $pageNameElements[0]; } else { throw new MWException(wfMessage('sf_autoedit_notargetspecified')->parse()); } $targetTitle = null; } else { $targetNameFormula = null; $targetTitle = Title::newFromText($targetName); } $preloadContent = ''; // save $wgRequest for later restoration $oldRequest = $wgRequest; $pageExists = false; // preload data if not explicitly excluded and if the preload page exists if (!isset($this->mOptions['preload']) || $this->mOptions['preload'] !== false) { if (isset($this->mOptions['preload']) && is_string($this->mOptions['preload'])) { $preloadTitle = Title::newFromText($this->mOptions['preload']); } else { $preloadTitle = Title::newFromText($targetName); } if ($preloadTitle !== null && $preloadTitle->exists()) { // the content of the page that was specified to be used for preloading $preloadContent = $this->getTextForPage($preloadTitle); $pageExists = true; } else { if (isset($this->mOptions['preload'])) { $this->logMessage(wfMessage('sf_autoedit_invalidpreloadspecified', $this->mOptions['preload'])->parse(), self::WARNING); } } } // Allow extensions to set/change the preload text, for new // pages. if (!$pageExists) { Hooks::run('sfEditFormPreloadText', array(&$preloadContent, $targetTitle, $formTitle)); } // Flag to keep track of formHTML() runs. $formHtmlHasRun = false; if ($preloadContent !== '') { // @HACK - we need to set this for the preload to take // effect in the form. $pageExists = true; // Spoof $wgRequest for SFFormPrinter::formHTML(). if (isset($_SESSION)) { $wgRequest = new FauxRequest($this->mOptions, true, $_SESSION); } else { $wgRequest = new FauxRequest($this->mOptions, true); } // Call SFFormPrinter::formHTML() to get at the form // HTML of the existing page. list($formHTML, $formJS, $targetContent, $form_page_title, $generatedTargetNameFormula) = $sfgFormPrinter->formHTML($formContent, $isFormSubmitted, $pageExists, $formArticleId, $preloadContent, $targetName, $targetNameFormula); // Parse the data to be preloaded from the form HTML of // the existing page. $data = $this->parseDataFromHTMLFrag($formHTML); // ...and merge/overwrite it with the new data. $this->mOptions = SFUtils::array_merge_recursive_distinct($data, $this->mOptions); } // We already preloaded stuff for saving/previewing - // do not do this again. if ($isFormSubmitted && !$wgRequest->getCheck('partial')) { $preloadContent = ''; $pageExists = false; } else { // Source of the data is a page. $pageExists = is_a($targetTitle, 'Title') && $targetTitle->exists(); } // Spoof $wgRequest for SFFormPrinter::formHTML(). if (isset($_SESSION)) { $wgRequest = new FauxRequest($this->mOptions, true, $_SESSION); } else { $wgRequest = new FauxRequest($this->mOptions, true); } // get wikitext for submitted data and form list($formHTML, $formJS, $targetContent, $generatedFormName, $generatedTargetNameFormula) = $sfgFormPrinter->formHTML($formContent, $isFormSubmitted, $pageExists, $formArticleId, $preloadContent, $targetName, $targetNameFormula); // Restore original request. $wgRequest = $oldRequest; if ($generatedFormName !== '') { $formTitle = Title::newFromText($generatedFormName); $this->mOptions['formtitle'] = $formTitle->getText(); } $this->mOptions['formHTML'] = $formHTML; $this->mOptions['formJS'] = $formJS; if ($isFormSubmitted) { // If the target page was not specified, see if // something was generated from the target name formula. if ($this->mOptions['target'] === '') { // If no name was generated, we cannot save => give up if ($generatedTargetNameFormula === '') { throw new MWException(wfMessage('sf_autoedit_notargetspecified')->parse()); } $this->mOptions['target'] = $this->generateTargetName($generatedTargetNameFormula); } // Lets other code process additional form-definition syntax Hooks::run('sfWritePageData', array($this->mOptions['form'], Title::newFromText($this->mOptions['target']), &$targetContent)); $editor = $this->setupEditPage($targetContent); // Perform the requested action. if ($this->mAction === self::ACTION_PREVIEW) { $this->doPreview($editor); } else { if ($this->mAction === self::ACTION_DIFF) { $this->doDiff($editor); } else { $this->doStore($editor); } } } else { if ($this->mAction === self::ACTION_FORMEDIT) { $parserOutput = $wgParser->getOutput(); if (method_exists($wgOut, 'addParserOutputMetadata')) { $wgOut->addParserOutputMetadata($parserOutput); } else { $wgOut->addParserOutputNoText($parserOutput); } $this->doFormEdit($formHTML, $formJS); } } }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param array $limit set of restriction keys * @param $reason String * @param &$cascade Integer. Set to false if cascading protection isn't allowed. * @param array $expiry per restriction type expiration * @param $user User The user updating the restrictions * @return Status */ public function doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user) { global $wgContLang, $wgCascadingRestrictionLevels; if (wfReadOnly()) { return Status::newFatal('readonlytext', wfReadOnlyReason()); } $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->getId(); if (!$cascade) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); // @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); // we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB(DB_MASTER); foreach ($restrictionTypes as $action) { if (!isset($expiry[$action])) { $expiry[$action] = $dbw->getInfinity(); } if (!isset($limit[$action])) { $limit[$action] = ''; } elseif ($limit[$action] != '') { $protect = true; } // Get current restrictions on $action $current = implode('', $this->mTitle->getRestrictions($action)); if ($current != '') { $isProtected = true; } if ($limit[$action] != $current) { $changed = true; } elseif ($limit[$action] != '') { // Only check expiry change if the action is actually being // protected, since expiry does nothing on an not-protected // action. if ($this->mTitle->getRestrictionExpiry($action) != $expiry[$action]) { $changed = true; } } } if (!$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade) { $changed = true; } // If nothing has changed, do nothing if (!$changed) { return Status::newGood(); } if (!$protect) { // No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ($isProtected) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } $encodedExpiry = array(); $protectDescription = ''; # Some bots may parse IRC lines, which are generated from log entries which contain plain # protect description text. Keep them in old format to avoid breaking compatibility. # TODO: Fix protection log to store structured description and format it on-the-fly. $protectDescriptionLog = ''; foreach ($limit as $action => $restrictions) { $encodedExpiry[$action] = $dbw->encodeExpiry($expiry[$action]); if ($restrictions != '') { $protectDescriptionLog .= $wgContLang->getDirMark() . "[{$action}={$restrictions}] ("; # $action is one of $wgRestrictionTypes = array( 'create', 'edit', 'move', 'upload' ). # All possible message keys are listed here for easier grepping: # * restriction-create # * restriction-edit # * restriction-move # * restriction-upload $actionText = wfMessage('restriction-' . $action)->inContentLanguage()->text(); # $restrictions is one of $wgRestrictionLevels = array( '', 'autoconfirmed', 'sysop' ), # with '' filtered out. All possible message keys are listed below: # * protect-level-autoconfirmed # * protect-level-sysop $restrictionsText = wfMessage('protect-level-' . $restrictions)->inContentLanguage()->text(); if ($encodedExpiry[$action] != 'infinity') { $expiryText = wfMessage('protect-expiring', $wgContLang->timeanddate($expiry[$action], false, false), $wgContLang->date($expiry[$action], false, false), $wgContLang->time($expiry[$action], false, false))->inContentLanguage()->text(); } else { $expiryText = wfMessage('protect-expiry-indefinite')->inContentLanguage()->text(); } if ($protectDescription !== '') { $protectDescription .= wfMessage('word-separator')->inContentLanguage()->text(); } $protectDescription .= wfMessage('protect-summary-desc')->params($actionText, $restrictionsText, $expiryText)->inContentLanguage()->text(); $protectDescriptionLog .= $expiryText . ') '; } } $protectDescriptionLog = trim($protectDescriptionLog); if ($id) { // Protection of existing page if (!wfRunHooks('ArticleProtect', array(&$this, &$user, $limit, $reason))) { return Status::newGood(); } // Only certain restrictions can cascade... Otherwise, users who cannot normally protect pages // could "protect" them by transcluding them on protected pages they are allowed to edit. $editrestriction = isset($limit['edit']) ? array($limit['edit']) : $this->mTitle->getRestrictions('edit'); $cascadingRestrictionLevels = $wgCascadingRestrictionLevels; if (in_array('sysop', $cascadingRestrictionLevels)) { $cascadingRestrictionLevels[] = 'protect'; // backwards compatibility } // The schema allows multiple restrictions if (!array_intersect($editrestriction, $cascadingRestrictionLevels)) { $cascade = false; } // Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascade && $action == 'edit' ? 1 : 0, 'pr_expiry' => $encodedExpiry[$action]), __METHOD__); } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); } } // Prepare a null revision to be added to the history $editComment = $wgContLang->ucfirst(wfMessage($revCommentMsg, $this->mTitle->getPrefixedText())->inContentLanguage()->text()); if ($reason) { $editComment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason; } if ($protectDescription) { $editComment .= wfMessage('word-separator')->inContentLanguage()->text(); $editComment .= wfMessage('parentheses')->params($protectDescription)->inContentLanguage()->text(); } if ($cascade) { $editComment .= wfMessage('word-separator')->inContentLanguage()->text(); $editComment .= wfMessage('brackets')->params(wfMessage('protect-summary-cascade')->inContentLanguage()->text())->inContentLanguage()->text(); } // Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $editComment, true); $nullRevId = $nullRevision->insertOn($dbw); $latest = $this->getLatest(); // Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_latest' => $nullRevId), array('page_id' => $id), __METHOD__); wfRunHooks('NewRevisionFromEditComplete', array($this, $nullRevision, $latest, $user)); wfRunHooks('ArticleProtectComplete', array(&$this, &$user, $limit, $reason)); } else { // Protection of non-existing page (also known as "title protection") // Cascade protection is meaningless in this case $cascade = false; if ($limit['create'] != '') { $dbw->replace('protected_titles', array(array('pt_namespace', 'pt_title')), array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->encodeExpiry(wfTimestampNow()), 'pt_expiry' => $encodedExpiry['create'], 'pt_user' => $user->getId(), 'pt_reason' => $reason), __METHOD__); } else { $dbw->delete('protected_titles', array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey()), __METHOD__); } } $this->mTitle->flushRestrictions(); InfoAction::invalidateCache($this->mTitle); if ($logAction == 'unprotect') { $logParams = array(); } else { $logParams = array($protectDescriptionLog, $cascade ? 'cascade' : ''); } // Update the protection log $log = new LogPage('protect'); $log->addEntry($logAction, $this->mTitle, trim($reason), $logParams, $user); return Status::newGood(); }
/** * Auto-create an account, and log into that account * @param User $user User to auto-create * @param string $source What caused the auto-creation? This must be the ID * of a PrimaryAuthenticationProvider or the constant self::AUTOCREATE_SOURCE_SESSION. * @param bool $login Whether to also log the user in * @return Status Good if user was created, Ok if user already existed, otherwise Fatal */ public function autoCreateUser(User $user, $source, $login = true) { if ($source !== self::AUTOCREATE_SOURCE_SESSION && !$this->getAuthenticationProvider($source) instanceof PrimaryAuthenticationProvider) { throw new \InvalidArgumentException("Unknown auto-creation source: {$source}"); } $username = $user->getName(); // Try the local user from the slave DB $localId = User::idFromName($username); $flags = User::READ_NORMAL; // Fetch the user ID from the master, so that we don't try to create the user // when they already exist, due to replication lag // @codeCoverageIgnoreStart if (!$localId && wfGetLB()->getReaderIndex() != 0) { $localId = User::idFromName($username, User::READ_LATEST); $flags = User::READ_LATEST; } // @codeCoverageIgnoreEnd if ($localId) { $this->logger->debug(__METHOD__ . ': {username} already exists locally', ['username' => $username]); $user->setId($localId); $user->loadFromId($flags); if ($login) { $this->setSessionDataForUser($user); } $status = Status::newGood(); $status->warning('userexists'); return $status; } // Wiki is read-only? if (wfReadOnly()) { $this->logger->debug(__METHOD__ . ': denied by wfReadOnly(): {reason}', ['username' => $username, 'reason' => wfReadOnlyReason()]); $user->setId(0); $user->loadFromId(); return Status::newFatal('readonlytext', wfReadOnlyReason()); } // Check the session, if we tried to create this user already there's // no point in retrying. $session = $this->request->getSession(); if ($session->get('AuthManager::AutoCreateBlacklist')) { $this->logger->debug(__METHOD__ . ': blacklisted in session {sessionid}', ['username' => $username, 'sessionid' => $session->getId()]); $user->setId(0); $user->loadFromId(); $reason = $session->get('AuthManager::AutoCreateBlacklist'); if ($reason instanceof StatusValue) { return Status::wrap($reason); } else { return Status::newFatal($reason); } } // Is the username creatable? if (!User::isCreatableName($username)) { $this->logger->debug(__METHOD__ . ': name "{username}" is not creatable', ['username' => $username]); $session->set('AuthManager::AutoCreateBlacklist', 'noname', 600); $user->setId(0); $user->loadFromId(); return Status::newFatal('noname'); } // Is the IP user able to create accounts? $anon = new User(); if (!$anon->isAllowedAny('createaccount', 'autocreateaccount')) { $this->logger->debug(__METHOD__ . ': IP lacks the ability to create or autocreate accounts', ['username' => $username, 'ip' => $anon->getName()]); $session->set('AuthManager::AutoCreateBlacklist', 'authmanager-autocreate-noperm', 600); $session->persist(); $user->setId(0); $user->loadFromId(); return Status::newFatal('authmanager-autocreate-noperm'); } // Avoid account creation races on double submissions $cache = \ObjectCache::getLocalClusterInstance(); $lock = $cache->getScopedLock($cache->makeGlobalKey('account', md5($username))); if (!$lock) { $this->logger->debug(__METHOD__ . ': Could not acquire account creation lock', ['user' => $username]); $user->setId(0); $user->loadFromId(); return Status::newFatal('usernameinprogress'); } // Denied by providers? $providers = $this->getPreAuthenticationProviders() + $this->getPrimaryAuthenticationProviders() + $this->getSecondaryAuthenticationProviders(); foreach ($providers as $provider) { $status = $provider->testUserForCreation($user, $source); if (!$status->isGood()) { $ret = Status::wrap($status); $this->logger->debug(__METHOD__ . ': Provider denied creation of {username}: {reason}', ['username' => $username, 'reason' => $ret->getWikiText(null, null, 'en')]); $session->set('AuthManager::AutoCreateBlacklist', $status, 600); $user->setId(0); $user->loadFromId(); return $ret; } } // Ignore warnings about master connections/writes...hard to avoid here \Profiler::instance()->getTransactionProfiler()->resetExpectations(); $backoffKey = wfMemcKey('AuthManager', 'autocreate-failed', md5($username)); if ($cache->get($backoffKey)) { $this->logger->debug(__METHOD__ . ': {username} denied by prior creation attempt failures', ['username' => $username]); $user->setId(0); $user->loadFromId(); return Status::newFatal('authmanager-autocreate-exception'); } // Checks passed, create the user... $from = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'CLI'; $this->logger->info(__METHOD__ . ': creating new user ({username}) - from: {from}', ['username' => $username, 'from' => $from]); try { $status = $user->addToDatabase(); if (!$status->isOk()) { // double-check for a race condition (T70012) $localId = User::idFromName($username, User::READ_LATEST); if ($localId) { $this->logger->info(__METHOD__ . ': {username} already exists locally (race)', ['username' => $username]); $user->setId($localId); $user->loadFromId(User::READ_LATEST); if ($login) { $this->setSessionDataForUser($user); } $status = Status::newGood(); $status->warning('userexists'); } else { $this->logger->error(__METHOD__ . ': {username} failed with message {message}', ['username' => $username, 'message' => $status->getWikiText(null, null, 'en')]); $user->setId(0); $user->loadFromId(); } return $status; } } catch (\Exception $ex) { $this->logger->error(__METHOD__ . ': {username} failed with exception {exception}', ['username' => $username, 'exception' => $ex]); // Do not keep throwing errors for a while $cache->set($backoffKey, 1, 600); // Bubble up error; which should normally trigger DB rollbacks throw $ex; } $this->setDefaultUserOptions($user, true); // Inform the providers $this->callMethodOnProviders(6, 'autoCreatedAccount', [$user, $source]); \Hooks::run('AuthPluginAutoCreate', [$user], '1.27'); \Hooks::run('LocalUserCreated', [$user, true]); $user->saveSettings(); // Update user count \DeferredUpdates::addUpdate(new \SiteStatsUpdate(0, 0, 0, 0, 1)); // Watch user's userpage and talk page $user->addWatch($user->getUserPage(), User::IGNORE_USER_RIGHTS); // Log the creation if ($this->config->get('NewUserLog')) { $logEntry = new \ManualLogEntry('newusers', 'autocreate'); $logEntry->setPerformer($user); $logEntry->setTarget($user->getUserPage()); $logEntry->setComment(''); $logEntry->setParameters(['4::userid' => $user->getId()]); $logid = $logEntry->insert(); } if ($login) { $this->setSessionDataForUser($user); } return Status::newGood(); }
/** * Render template for <body> tag content */ public function executeEditPage() { wfProfileIn(__METHOD__); $helper = EditPageLayoutHelper::getInstance(); $editPage = $helper->getEditPage(); $this->showPreview = true; if ($helper->fullScreen) { $wgJsMimeType = $this->wg->JsMimeType; // add stylesheet $this->wg->Out->addStyle(AssetsManager::getInstance()->getSassCommonURL('extensions/wikia/EditPageLayout/css/EditPageLayout.scss')); if ($helper->isCodeSyntaxHighlightingEnabled($editPage->getTitle())) { $this->wg->Out->addScript("<script type=\"{$wgJsMimeType}\" src=\"/resources/Ace/ace.js\"></script>"); $srcs = AssetsManager::getInstance()->getGroupCommonURL('ace_editor_js'); OasisController::addBodyClass('codeeditor'); $this->showPreview = $helper->isCodePageWithPreview($editPage->getTitle()); } else { $packageName = 'epl'; if (class_exists('RTE') && RTE::isEnabled() && !$editPage->isReadOnlyPage()) { $packageName = 'eplrte'; } $srcs = AssetsManager::getInstance()->getGroupCommonURL($packageName); } foreach ($srcs as $src) { $this->wg->Out->addScript("<script type=\"{$wgJsMimeType}\" src=\"{$src}\"></script>"); } } // render WikiLogo $response = $this->app->sendRequest('WikiHeader', 'Wordmark'); // move wordmark data $this->wordmark = $response->getData(); // render global and user navigation $this->header = F::app()->renderView('GlobalNavigation', 'index'); // Editing [foo] $this->title = $editPage->getEditedTitle(); $section = $this->wg->Request->getVal('section'); // Is user logged in? $this->isLoggedIn = $this->wg->User->isLoggedIn(); // Can the user minor edit? $this->canMinorEdit = $this->title->exists() && $this->isLoggedIn && $this->wg->User->isAllowed('minoredit'); // Text for Edit summary label $wpSummaryLabelText = 'editpagelayout-edit-summary-label'; // Should show mobile preview icon $this->showMobilePreview = $helper->showMobilePreview($editPage->getTitle()); if ($section == 'new') { $msgKey = 'editingcomment'; // If adding new section to page, change label text (BugId: 7243) $wpSummaryLabelText = 'editpagelayout-subject-headline-label'; } else { if (is_numeric($section)) { $msgKey = 'editingsection'; } else { $msgKey = 'editing'; } } // title $this->titleText = $this->title->getPrefixedText(); if ($this->titleText == '') { $this->titleText = ' '; } // limit title length if (mb_strlen($this->titleText) > self::TITLE_MAX_LENGTH) { $this->titleShortText = htmlspecialchars(mb_substr($this->titleText, 0, self::TITLE_MAX_LENGTH)) . '…'; } else { $this->titleShortText = htmlspecialchars($this->titleText); } $this->editing = wfMessage($msgKey, '')->escaped(); $this->wpSummaryLabelText = wfMessage($wpSummaryLabelText)->escaped(); // render help link and point the link to new tab $this->helpLink = wfMessage('editpagelayout-helpLink')->parse(); $this->helpLink = str_replace('<a ', '<a target="_blank" ', $this->helpLink); // action for edit form $this->editFormAction = $editPage->getFormAction(); // preloads $this->editPagePreloads = $editPage->getEditPagePreloads(); // minor edit checkbox (BugId:6461) $this->minorEditCheckbox = !empty($editPage->minoredit); // summary box $this->summaryBox = $editPage->renderSummaryBox(); // extra checkboxes $this->customCheckboxes = $editPage->getCustomCheckboxes(); // dismissable notifications $this->notices = $editPage->getNotices(); $this->noticesHtml = $editPage->getNoticesHtml(); // notifications link (BugId:7951) $this->notificationsLink = count($this->notices) == 0 ? wfMessage('editpagelayout-notificationsLink-none')->escaped() : wfMessage('editpagelayout-notificationsLink', count($this->notices))->parse(); // check if we're in read only mode // disable edit form when in read-only mode if (wfReadOnly()) { $this->bodytext = '<div id="mw-read-only-warning" class="WikiaArticle">' . wfMessage('oasis-editpage-readonlywarning', wfReadOnlyReason())->escaped() . '</div>'; wfDebug(__METHOD__ . ": edit form disabled because read-only mode is on\n"); } $this->hideTitle = $editPage->hideTitle; wfRunHooks('EditPageLayoutExecute', array($this)); wfProfileOut(__METHOD__); }
/** * Display a page stating that the Wiki is in read-only mode, * and optionally show the source of the page that the user * was trying to edit. Should only be called (for this * purpose) after wfReadOnly() has returned true. * * For historical reasons, this function is _also_ used to * show the error message when a user tries to edit a page * they are not allowed to edit. (Unless it's because they're * blocked, then we show blockedPage() instead.) In this * case, the second parameter should be set to true and a list * of reasons supplied as the third parameter. * * @todo Needs to be split into multiple functions. * * @param string $source Source code to show (or null). * @param bool $protected Is this a permissions error? * @param array $reasons List of reasons for this error, as returned by Title::getUserPermissionsErrors(). */ public function readOnlyPage($source = null, $protected = false, $reasons = array(), $action = null) { global $wgUser, $wgTitle; $skin = $wgUser->getSkin(); $this->setRobotPolicy('noindex,nofollow'); $this->setArticleRelated(false); // If no reason is given, just supply a default "I can't let you do // that, Dave" message. Should only occur if called by legacy code. if ($protected && empty($reasons)) { $reasons[] = array('badaccess-group0'); } if (!empty($reasons)) { // Permissions error if ($source) { $this->setPageTitle(wfMsg('viewsource')); $this->setSubtitle(wfMsg('viewsourcefor', $skin->makeKnownLinkObj($wgTitle))); } else { $this->setPageTitle(wfMsg('badaccess')); } $this->addWikiText($this->formatPermissionsErrorMessage($reasons, $action)); } else { // Wiki is read only $this->setPageTitle(wfMsg('readonly')); $reason = wfReadOnlyReason(); $this->wrapWikiMsg('<div class="mw-readonly-error">$1</div>', array('readonlytext', $reason)); } // Show source, if supplied if (is_string($source)) { $this->addWikiMsg('viewsourcetext'); $text = Xml::openElement('textarea', array('id' => 'wpTextbox1', 'name' => 'wpTextbox1', 'cols' => $wgUser->getOption('cols'), 'rows' => $wgUser->getOption('rows'), 'readonly' => 'readonly')); $text .= htmlspecialchars($source); $text .= Xml::closeElement('textarea'); $this->addHTML($text); // Show templates used by this article $skin = $wgUser->getSkin(); $article = new Article($wgTitle); $this->addHTML("<div class='templatesUsed'>\n{$skin->formatTemplates($article->getUsedTemplates())}\n</div>\n"); } # If the title doesn't exist, it's fairly pointless to print a return # link to it. After all, you just tried editing it and couldn't, so # what's there to do there? if ($wgTitle->exists()) { $this->returnToMain(null, $wgTitle); } }
/** * @return bool */ protected function showHeader() { global $wgOut, $wgUser, $wgMaxArticleSize, $wgLang; global $wgAllowUserCss, $wgAllowUserJs; if ($this->mTitle->isTalkPage()) { $wgOut->addWikiMsg('talkpagetext'); } // Add edit notices $wgOut->addHTML(implode("\n", $this->mTitle->getEditNotices($this->oldid))); if ($this->isConflict) { $wgOut->wrapWikiMsg("<div class='mw-explainconflict'>\n\$1\n</div>", 'explainconflict'); $this->edittime = $this->mArticle->getTimestamp(); } else { if ($this->section != '' && !$this->isSectionEditSupported()) { // We use $this->section to much before this and getVal('wgSection') directly in other places // at this point we can't reset $this->section to '' to fallback to non-section editing. // Someone is welcome to try refactoring though $wgOut->showErrorPage('sectioneditnotsupported-title', 'sectioneditnotsupported-text'); return false; } if ($this->section != '' && $this->section != 'new') { if (!$this->summary && !$this->preview && !$this->diff) { $sectionTitle = self::extractSectionTitle($this->textbox1); //FIXME: use Content object if ($sectionTitle !== false) { $this->summary = "/* {$sectionTitle} */ "; } } } if ($this->missingComment) { $wgOut->wrapWikiMsg("<div id='mw-missingcommenttext'>\n\$1\n</div>", 'missingcommenttext'); } if ($this->missingSummary && $this->section != 'new') { $wgOut->wrapWikiMsg("<div id='mw-missingsummary'>\n\$1\n</div>", 'missingsummary'); } if ($this->missingSummary && $this->section == 'new') { $wgOut->wrapWikiMsg("<div id='mw-missingcommentheader'>\n\$1\n</div>", 'missingcommentheader'); } if ($this->blankArticle) { $wgOut->wrapWikiMsg("<div id='mw-blankarticle'>\n\$1\n</div>", 'blankarticle'); } if ($this->hookError !== '') { $wgOut->addWikiText($this->hookError); } if (!$this->checkUnicodeCompliantBrowser()) { $wgOut->addWikiMsg('nonunicodebrowser'); } if ($this->section != 'new') { $revision = $this->mArticle->getRevisionFetched(); if ($revision) { // Let sysop know that this will make private content public if saved if (!$revision->userCan(Revision::DELETED_TEXT, $wgUser)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1\n</div>\n", 'rev-deleted-text-permission'); } elseif ($revision->isDeleted(Revision::DELETED_TEXT)) { $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1\n</div>\n", 'rev-deleted-text-view'); } if (!$revision->isCurrent()) { $this->mArticle->setOldSubtitle($revision->getId()); $wgOut->addWikiMsg('editingold'); } } elseif ($this->mTitle->exists()) { // Something went wrong $wgOut->wrapWikiMsg("<div class='errorbox'>\n\$1\n</div>\n", array('missing-revision', $this->oldid)); } } } if (wfReadOnly()) { $wgOut->wrapWikiMsg("<div id=\"mw-read-only-warning\">\n\$1\n</div>", array('readonlywarning', wfReadOnlyReason())); } elseif ($wgUser->isAnon()) { if ($this->formtype != 'preview') { $wgOut->wrapWikiMsg("<div id='mw-anon-edit-warning'>\n\$1\n</div>", array('anoneditwarning', '{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}', '{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}')); } else { $wgOut->wrapWikiMsg("<div id=\"mw-anon-preview-warning\">\n\$1</div>", 'anonpreviewwarning'); } } else { if ($this->isCssJsSubpage) { # Check the skin exists if ($this->isWrongCaseCssJsPage) { $wgOut->wrapWikiMsg("<div class='error' id='mw-userinvalidcssjstitle'>\n\$1\n</div>", array('userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage())); } if ($this->formtype !== 'preview') { if ($this->isCssSubpage && $wgAllowUserCss) { $wgOut->wrapWikiMsg("<div id='mw-usercssyoucanpreview'>\n\$1\n</div>", array('usercssyoucanpreview')); } if ($this->isJsSubpage && $wgAllowUserJs) { $wgOut->wrapWikiMsg("<div id='mw-userjsyoucanpreview'>\n\$1\n</div>", array('userjsyoucanpreview')); } } } } if ($this->mTitle->isProtected('edit') && MWNamespace::getRestrictionLevels($this->mTitle->getNamespace()) !== array('')) { # Is the title semi-protected? if ($this->mTitle->isSemiProtected()) { $noticeMsg = 'semiprotectedpagewarning'; } else { # Then it must be protected based on static groups (regular) $noticeMsg = 'protectedpagewarning'; } LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle, '', array('lim' => 1, 'msgKey' => array($noticeMsg))); } if ($this->mTitle->isCascadeProtected()) { # Is this page under cascading protection from some source pages? list($cascadeSources, ) = $this->mTitle->getCascadeProtectionSources(); $notice = "<div class='mw-cascadeprotectedwarning'>\n\$1\n"; $cascadeSourcesCount = count($cascadeSources); if ($cascadeSourcesCount > 0) { # Explain, and list the titles responsible foreach ($cascadeSources as $page) { $notice .= '* [[:' . $page->getPrefixedText() . "]]\n"; } } $notice .= '</div>'; $wgOut->wrapWikiMsg($notice, array('cascadeprotectedwarning', $cascadeSourcesCount)); } if (!$this->mTitle->exists() && $this->mTitle->getRestrictions('create')) { LogEventsList::showLogExtract($wgOut, 'protect', $this->mTitle, '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('titleprotectedwarning'), 'wrap' => "<div class=\"mw-titleprotectedwarning\">\n\$1</div>")); } if ($this->kblength === false) { $this->kblength = (int) (strlen($this->textbox1) / 1024); } if ($this->tooBig || $this->kblength > $wgMaxArticleSize) { $wgOut->wrapWikiMsg("<div class='error' id='mw-edit-longpageerror'>\n\$1\n</div>", array('longpageerror', $wgLang->formatNum($this->kblength), $wgLang->formatNum($wgMaxArticleSize))); } else { if (!wfMessage('longpage-hint')->isDisabled()) { $wgOut->wrapWikiMsg("<div id='mw-edit-longpage-hint'>\n\$1\n</div>", array('longpage-hint', $wgLang->formatSize(strlen($this->textbox1)), strlen($this->textbox1))); } } # Add header copyright warning $this->showHeaderCopyrightWarning(); return true; }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param $limit Array: set of restriction keys * @param $reason String * @param &$cascade Integer. Set to false if cascading protection isn't allowed. * @param $expiry Array: per restriction type expiration * @param $user User The user updating the restrictions * @return Status */ public function doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user) { global $wgContLang; if (wfReadOnly()) { return Status::newFatal('readonlytext', wfReadOnlyReason()); } $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->mTitle->getArticleID(); if (!$cascade) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); # @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); # we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB(DB_MASTER); foreach ($restrictionTypes as $action) { if (!isset($expiry[$action])) { $expiry[$action] = $dbw->getInfinity(); } if (!isset($limit[$action])) { $limit[$action] = ''; } elseif ($limit[$action] != '') { $protect = true; } # Get current restrictions on $action $current = implode('', $this->mTitle->getRestrictions($action)); if ($current != '') { $isProtected = true; } if ($limit[$action] != $current) { $changed = true; } elseif ($limit[$action] != '') { # Only check expiry change if the action is actually being # protected, since expiry does nothing on an not-protected # action. if ($this->mTitle->getRestrictionExpiry($action) != $expiry[$action]) { $changed = true; } } } if (!$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade) { $changed = true; } # If nothing's changed, do nothing if (!$changed) { return Status::newGood(); } if (!$protect) { # No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ($isProtected) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } $encodedExpiry = array(); $protectDescription = ''; foreach ($limit as $action => $restrictions) { $encodedExpiry[$action] = $dbw->encodeExpiry($expiry[$action]); if ($restrictions != '') { $protectDescription .= $wgContLang->getDirMark() . "[{$action}={$restrictions}] ("; if ($encodedExpiry[$action] != 'infinity') { $protectDescription .= wfMessage('protect-expiring', $wgContLang->timeanddate($expiry[$action], false, false), $wgContLang->date($expiry[$action], false, false), $wgContLang->time($expiry[$action], false, false))->inContentLanguage()->text(); } else { $protectDescription .= wfMessage('protect-expiry-indefinite')->inContentLanguage()->text(); } $protectDescription .= ') '; } } $protectDescription = trim($protectDescription); if ($id) { # Protection of existing page if (!wfRunHooks('ArticleProtect', array(&$this, &$user, $limit, $reason))) { return Status::newGood(); } # Only restrictions with the 'protect' right can cascade... # Otherwise, people who cannot normally protect can "protect" pages via transclusion $editrestriction = isset($limit['edit']) ? array($limit['edit']) : $this->mTitle->getRestrictions('edit'); # The schema allows multiple restrictions if (!in_array('protect', $editrestriction) && !in_array('sysop', $editrestriction)) { $cascade = false; } # Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascade && $action == 'edit' ? 1 : 0, 'pr_expiry' => $encodedExpiry[$action]), __METHOD__); } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); } } # Prepare a null revision to be added to the history $editComment = $wgContLang->ucfirst(wfMessage($revCommentMsg, $this->mTitle->getPrefixedText())->inContentLanguage()->text()); if ($reason) { $editComment .= ": {$reason}"; } if ($protectDescription) { $editComment .= " ({$protectDescription})"; } if ($cascade) { // FIXME: Should use 'brackets' message. $editComment .= ' [' . wfMessage('protect-summary-cascade')->inContentLanguage()->text() . ']'; } # Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $editComment, true); $nullRevId = $nullRevision->insertOn($dbw); $latest = $this->getLatest(); # Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_latest' => $nullRevId), array('page_id' => $id), __METHOD__); wfRunHooks('NewRevisionFromEditComplete', array($this, $nullRevision, $latest, $user)); wfRunHooks('ArticleProtectComplete', array(&$this, &$user, $limit, $reason)); } else { # Protection of non-existing page (also known as "title protection") # Cascade protection is meaningless in this case $cascade = false; if ($limit['create'] != '') { $dbw->replace('protected_titles', array(array('pt_namespace', 'pt_title')), array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->encodeExpiry(wfTimestampNow()), 'pt_expiry' => $encodedExpiry['create'], 'pt_user' => $user->getId(), 'pt_reason' => $reason), __METHOD__); } else { $dbw->delete('protected_titles', array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey()), __METHOD__); } } $this->mTitle->flushRestrictions(); if ($logAction == 'unprotect') { $logParams = array(); } else { $logParams = array($protectDescription, $cascade ? 'cascade' : ''); } # Update the protection log $log = new LogPage('protect'); $log->addEntry($logAction, $this->mTitle, trim($reason), $logParams, $user); return Status::newGood(); }
/** * This method will try to store the data in mOptions. * * It will return true on success or an error message on failure. * The used form and target page will be available in mOptions after * execution of the method. * * This method also sets HTTP response headers according to the result. * * @param bool $prefillFromExisting If this is set, existing values in the page will be used to prefill the form. * @return true or an error message */ public function storeSemanticData($prefillFromExisting = true) { global $wgOut, $wgRequest; // If the wiki is read-only we might as well stop right away if (wfReadOnly()) { return $this->reportError(wfMsg('sf_autoedit_readonly', wfReadOnlyReason())); } // ensure 'form' key exists if (!array_key_exists('form', $this->mOptions)) { $this->mOptions['form'] = null; } // ensure 'target' key exists if (!array_key_exists('target', $this->mOptions)) { $this->mOptions['target'] = null; } // If we have no target article and no form we might as well stop right away if (!$this->mOptions['target'] && !$this->mOptions['form']) { return $this->reportError(wfMsg('sf_autoedit_notargetspecified')); } // check if form was specified if (!$this->mOptions['form']) { // If no form was specified, find the default one for // this page. $title = Title::newFromText($this->mOptions['target']); $form_names = SFFormLinker::getDefaultFormsForPage($title); // if no form can be found, return if (count($form_names) == 0) { return $this->reportError(wfMsg('sf_autoedit_noformfound')); } // if more than one form found, return if (count($form_names) > 1) { return $this->reportError(wfMsg('sf_autoedit_toomanyformsfound')); } // There should now be exactly one form. $this->mOptions['form'] = $form_names[0]; } // we only care for the form's body $wgOut->setArticleBodyOnly(true); $formedit = new SFFormEdit(); $data = array(); $oldRequest = $wgRequest; // Get the form definition and target page (if there is one), // as specified in the options string, then create the actual // HTML form from them, and call that form to modify or create // the page. if ($prefillFromExisting) { $wgRequest = new FauxRequest($this->mOptions, true); // get the Semantic Form if ($this->mOptions['target']) { $formedit->execute($this->mOptions['form'] . '/' . $this->mOptions['target']); } else { $formedit->execute($this->mOptions['form']); } // extract its data $form = $this->parseDataFromHTMLFrag($data, trim($wgOut->getHTML()), 'sfForm'); if (!$form) { // something went wrong $wgRequest = $oldRequest; return $this->reportError(wfMsg('sf_autoedit_nosemanticform', array($this->mOptions['target'], $this->mOptions['form']))); } } else { self::addToArray($data, "wpSave", "Save"); } // and modify as specified $data = SFUtils::array_merge_recursive_distinct($data, $this->mOptions); //////////////////////////////////////////////////////////////////////// // Store the modified form // $wgOut->clearHTML(); $wgRequest = new FauxRequest($data, true); // get the MW form if ($this->mOptions['target']) { $formedit->execute($this->mOptions['form'] . '/' . $this->mOptions['target'], false); } else { $formedit->execute($this->mOptions['form'], false); } $this->mOptions['form'] = $formedit->mForm; $this->mOptions['target'] = $formedit->mTarget; $wgRequest = $oldRequest; if ($formedit->mError) { return $this->reportError($formedit->mError); } else { if (!headers_sent()) { header("X-Location: " . $wgOut->getRedirect()); header("X-Form: " . $formedit->mForm); header("X-Target: " . $formedit->mTarget); } if ($this->isApiQuery()) { $this->getResult()->addValue(null, 'result', array('code' => '200', 'location' => $wgOut->getRedirect(), 'form' => $formedit->mForm, 'target' => $formedit->mTarget)); } } return true; }
/** * Check whether the wiki is in read-only mode. * * @return bool */ function wfReadOnly() { return wfReadOnlyReason() !== false; }
/** * @param $url string * @return Mixed|String */ function fetchScaryTemplateMaybeFromCache($url) { global $wgTranscludeCacheExpiry; $dbr = wfGetDB(DB_SLAVE); $tsCond = $dbr->timestamp(time() - $wgTranscludeCacheExpiry); $obj = $dbr->selectRow('transcache', array('tc_time', 'tc_contents'), array('tc_url' => $url, "tc_time >= " . $dbr->addQuotes($tsCond))); if ($obj) { return $obj->tc_contents; } $text = Http::get($url); if (!$text) { # wikia start Wikia::log(__METHOD__, false, "Scary transclusion failed for <{$url}>"); # wikia end return wfMsgForContent('scarytranscludefailed', $url); } # wikia start if (wfReadOnly()) { return wfReadOnlyReason(); } # wikia end $dbw = wfGetDB(DB_MASTER); $dbw->replace('transcache', array('tc_url'), array('tc_url' => $url, 'tc_time' => $dbw->timestamp(time()), 'tc_contents' => $text)); return $text; }
/** * This function is the real heart of the entire Semantic Forms * extension. It handles two main actions: (1) displaying a form on the * screen, given a form definition and possibly page contents (if an * existing page is being edited); and (2) creating actual page * contents, if the form was already submitted by the user. * * It also does some related tasks, like figuring out the page name (if * only a page formula exists). */ function formHTML($form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $is_embedded = false) { global $wgRequest, $wgUser, $wgParser; global $sfgTabIndex; // used to represent the current tab index in the form global $sfgFieldNum; // used for setting various HTML IDs wfProfileIn(__METHOD__); // initialize some variables $sfgTabIndex = 1; $sfgFieldNum = 1; $source_page_matches_this_form = false; $form_page_title = null; $generated_page_name = $page_name_formula; // $form_is_partial is true if: // (a) 'partial' == 1 in the arguments // (b) 'partial form' is found in the form definition // in the latter case, it may remain false until close to the end of // the parsing, so we have to assume that it will become a possibility $form_is_partial = false; $new_text = ""; // flag for placing "<onlyinclude>" tags in form output $onlyinclude_free_text = false; // If we have existing content and we're not in an active replacement // situation, preserve the original content. We do this because we want // to pass the original content on IF this is a partial form. // TODO: A better approach here would be to pass the revision ID of the // existing page content through the replace value, which would // minimize the html traffic and would allow us to do a concurrent // update check. For now, we pass it through a hidden text field. if (!$wgRequest->getCheck('partial')) { $original_page_content = $existing_page_content; } else { $original_page_content = null; if ($wgRequest->getCheck('sf_free_text')) { $existing_page_content = $wgRequest->getVal('sf_free_text'); $form_is_partial = true; } } // Disable all form elements if user doesn't have edit // permission - two different checks are needed, because // editing permissions can be set in different ways. // HACK - sometimes we don't know the page name in advance, but // we still need to set a title here for testing permissions. if ($is_embedded) { // If this is an embedded form (probably a 'RunQuery'), // just use the name of the actual page we're on. global $wgTitle; $this->mPageTitle = $wgTitle; } elseif ($is_query) { $this->mPageTitle = Title::newFromText('RunQuery dummy title'); } elseif ($page_name === '' || $page_name === null) { $this->mPageTitle = Title::newFromText($wgRequest->getVal('namespace') . ":Semantic Forms permissions test"); } else { $this->mPageTitle = Title::newFromText($page_name); } global $wgOut; // show previous set of deletions for this page, if it's been deleted before if (!$form_submitted && ($this->mPageTitle && !$this->mPageTitle->exists())) { $this->showDeletionLog($wgOut); } // Unfortunately, we can't just call userCan() here because, // since MW 1.16, it has a bug in which it ignores a setting of // "$wgEmailConfirmToEdit = true;". Instead, we'll just get the // permission errors from the start, and use those to determine whether // the page is editable. if (!$is_query) { // $userCanEditPage = ( $wgUser->isAllowed( 'edit' ) && $this->mPageTitle->userCan( 'edit' ) ); $permissionErrors = $this->mPageTitle->getUserPermissionsErrors('edit', $wgUser); // The handling of $wgReadOnly and $wgReadOnlyFile // has to be done separately. if (wfReadOnly()) { global $wgReadOnly; $permissionErrors = array(array('readonlytext', array(wfReadOnlyReason()))); } $userCanEditPage = count($permissionErrors) == 0; wfRunHooks('sfUserCanEditPage', array($this->mPageTitle, &$userCanEditPage)); } $form_text = ""; if ($is_query || $userCanEditPage) { $form_is_disabled = false; // Show "Your IP address will be recorded" warning if // user is anonymous, and it's not a query - // wiki-text for bolding has to be replaced with HTML. if ($wgUser->isAnon() && !$is_query) { $anon_edit_warning = preg_replace("/'''(.*)'''/", "<strong>\$1</strong>", wfMsg('anoneditwarning')); $form_text .= "<p>{$anon_edit_warning}</p>\n"; } } else { $form_is_disabled = true; $wgOut->setPageTitle(wfMsg('badaccess')); $wgOut->addWikiText($wgOut->formatPermissionsErrorMessage($permissionErrors, 'edit')); $wgOut->addHTML("\n<hr />\n"); } // $oldParser = $wgParser; // $wgParser = unserialize( serialize( $oldParser ) ); // deep clone of parser if (!$wgParser->Options()) { $wgParser->Options(ParserOptions::newFromUser($wgUser)); } $wgParser->Title($this->mPageTitle); // $wgParser->clearState(); $form_def = SFFormUtils::getFormDefinition($wgParser, $form_def, $form_id); // Turn form definition file into an array of sections, one for each // template definition (plus the first section) $form_def_sections = array(); $start_position = 0; $section_start = 0; $free_text_was_included = false; $free_text_preload_page = null; $free_text_components = array(); $all_values_for_template = array(); // Unencode any HTML-encoded representations of curly brackets and // pipes - this is a hack to allow for forms to include templates // that themselves contain form elements - the escaping was needed // to make sure that those elements don't get parsed too early. $form_def = str_replace(array('{', '|', '}'), array('{', '|', '}'), $form_def); // And another hack - replace the 'free text' standard input with // a field declaration to get it to be handled as a field. $form_def = str_replace('standard input|free text', 'field|<freetext>', $form_def); while ($brackets_loc = strpos($form_def, "{{{", $start_position)) { $brackets_end_loc = strpos($form_def, "}}}", $brackets_loc); $bracketed_string = substr($form_def, $brackets_loc + 3, $brackets_end_loc - ($brackets_loc + 3)); $tag_components = SFUtils::getFormTagComponents($bracketed_string); $tag_title = trim($tag_components[0]); if ($tag_title == 'for template' || $tag_title == 'end template') { // Create a section for everything up to here $section = substr($form_def, $section_start, $brackets_loc - $section_start); $form_def_sections[] = $section; $section_start = $brackets_loc; } $start_position = $brackets_loc + 1; } // end while $form_def_sections[] = trim(substr($form_def, $section_start)); // Cycle through the form definition file, and possibly an // existing article as well, finding template and field // declarations and replacing them with form elements, either // blank or pre-populated, as appropriate. $all_fields = array(); $data_text = ""; $template_name = ""; $allow_multiple = false; $instance_num = 0; $all_instances_printed = false; $strict_parsing = false; // Placeholder name in the form $curPlaceholder = null; // Used to store the HTML code of the multiple template, to reinsert it into the right spot // This array will keep track of all the replaced @<name>@ strings $placeholderFields = array(); for ($section_num = 0; $section_num < count($form_def_sections); $section_num++) { $start_position = 0; $template_text = ""; // the append is there to ensure that the original // array doesn't get modified; is it necessary? $section = " " . $form_def_sections[$section_num]; $multipleTemplateString = ""; while ($brackets_loc = strpos($section, '{{{', $start_position)) { $brackets_end_loc = strpos($section, "}}}", $brackets_loc); $bracketed_string = substr($section, $brackets_loc + 3, $brackets_end_loc - ($brackets_loc + 3)); $tag_components = SFUtils::getFormTagComponents($bracketed_string); $tag_title = trim($tag_components[0]); // ===================================================== // for template processing // ===================================================== if ($tag_title == 'for template') { $old_template_name = $template_name; $template_name = trim($tag_components[1]); $tif = SFTemplateInForm::create($template_name); $query_template_name = str_replace(' ', '_', $template_name); $add_button_text = wfMsg('sf_formedit_addanother'); // Also replace periods with underlines, since that's what // POST does to strings anyway. $query_template_name = str_replace('.', '_', $query_template_name); // ...and escape apostrophes. $query_template_name = str_replace("'", "\\'", $query_template_name); // Cycle through the other components. for ($i = 2; $i < count($tag_components); $i++) { $component = $tag_components[$i]; if ($component == 'multiple') { $allow_multiple = true; } if ($component == 'strict') { $strict_parsing = true; } $sub_components = array_map('trim', explode('=', $component, 2)); if (count($sub_components) == 2) { if ($sub_components[0] == 'label') { $template_label = $sub_components[1]; } elseif ($sub_components[0] == 'add button text') { $add_button_text = $sub_components[1]; } elseif ($sub_components[0] == 'embed in field') { // Placeholder on form template level. Assume that the template form def // will have a multiple+placeholder parameters, and get the placeholder value. // We expect something like TemplateName[fieldName], and convert it to the // TemplateName___fieldName form used internally. preg_match('/\\s*(.*)\\[(.*)\\]\\s*/', $sub_components[1], $matches); $curPlaceholder = count($matches) > 2 ? self::placeholderFormat($matches[1], $matches[2]) : null; unset($matches); } } } // If this is the first instance, add // the label into the form, if there is // one, and add the appropriate wrapper // div, if this is a multiple-instance // template. if ($old_template_name != $template_name) { if (isset($template_label)) { $multipleTemplateString .= "<fieldset>\n"; $multipleTemplateString .= Html::element('legend', null, $template_label) . "\n"; } // If $curPlaceholder is set, it means we want to insert a // multiple template form's HTML into the main form's HTML. // So, the HTML will be stored in $multipleTemplateString. if ($allow_multiple) { $multipleTemplateString .= "\t" . '<div class="multipleTemplateWrapper">' . "\n"; $multipleTemplateString .= "\t" . '<div class="multipleTemplateList">' . "\n"; } } if ($curPlaceholder == null) { $form_text .= $multipleTemplateString; } $template_text .= "{{" . $template_name; $all_fields = $tif->getAllFields(); // remove template tag $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); $template_instance_query_values = $wgRequest->getArray($query_template_name); // If we are editing a page, and this // template can be found more than // once in that page, and multiple // values are allowed, repeat this // section. $existing_template_text = null; if ($source_is_page || $form_is_partial) { // Replace underlines with spaces in template name, to allow for // searching on either. $search_template_str = str_replace('_', ' ', $template_name); $preg_match_template_str = str_replace(array('/', '(', ')'), array('\\/', '\\(', '\\)'), $search_template_str); $found_instance = preg_match('/{{' . $preg_match_template_str . '\\s*[\\|}]/i', str_replace('_', ' ', $existing_page_content)); if ($allow_multiple) { // find instances of this template in the page - // if there's at least one, re-parse this section of the // definition form for the subsequent template instances in // this page; if there's none, don't include fields at all. // there has to be a more efficient way to handle multiple // instances of templates, one that doesn't involve re-parsing // the same tags, but I don't know what it is. if ($found_instance) { $instance_num++; } else { $all_instances_printed = true; } } // get the first instance of this template on the page being edited, // even if there are more if ($found_instance) { $matches = array(); $search_pattern = '/{{' . $preg_match_template_str . '\\s*[\\|}]/i'; $content_str = str_replace('_', ' ', $existing_page_content); preg_match($search_pattern, $content_str, $matches, PREG_OFFSET_CAPTURE); // is this check necessary? if (array_key_exists(0, $matches) && array_key_exists(1, $matches[0])) { $start_char = $matches[0][1]; $fields_start_char = $start_char + 2 + strlen($search_template_str); // Skip ahead to the first real character. while (in_array($existing_page_content[$fields_start_char], array(' ', '\\n'))) { $fields_start_char++; } // If the next character is a pipe, skip that too. if ($existing_page_content[$fields_start_char] == '|') { $fields_start_char++; } $template_contents = array('0' => ''); // Cycle through template call, splitting it up by pipes ('|'), // except when that pipe is part of a piped link. $field = ""; $uncompleted_square_brackets = 0; $uncompleted_curly_brackets = 2; $template_ended = false; for ($i = $fields_start_char; !$template_ended && $i < strlen($existing_page_content); $i++) { $c = $existing_page_content[$i]; if ($c == '[') { $uncompleted_square_brackets++; } elseif ($c == ']' && $uncompleted_square_brackets > 0) { $uncompleted_square_brackets--; } elseif ($c == '{') { $uncompleted_curly_brackets++; } elseif ($c == '}' && $uncompleted_curly_brackets > 0) { $uncompleted_curly_brackets--; } // handle an end to a field and/or template declaration $template_ended = $uncompleted_curly_brackets == 0 && $uncompleted_square_brackets == 0; $field_ended = $c == '|' && $uncompleted_square_brackets == 0 && $uncompleted_curly_brackets <= 2; if ($template_ended || $field_ended) { // if this was the last character in the template, remove // the closing curly brackets if ($template_ended) { $field = substr($field, 0, -1); } // either there's an equals sign near the beginning or not - // handling is similar in either way; if there's no equals // sign, the index of this field becomes the key $sub_fields = explode('=', $field, 2); if (count($sub_fields) > 1) { $template_contents[trim($sub_fields[0])] = trim($sub_fields[1]); } else { $template_contents[] = trim($sub_fields[0]); } $field = ''; } else { $field .= $c; } } // If there are uncompleted opening brackets, the whole form will get messed up - // display a warning. // (If there are too many *closing* brackets, some template stuff will end up in // the "free text" field - which is bad, but it's harder for the code to detect // the problem - though hopefully, easier for users.) if ($uncompleted_curly_brackets > 0 || $uncompleted_square_brackets > 0) { $form_text .= "\t" . '<div class="warningbox">' . wfMsg('sf_formedit_mismatchedbrackets', $this->mPageTitle->getFullURL(array('action' => 'edit'))) . "</div>\n<br clear=\"both\" />\n"; } $existing_template_text = substr($existing_page_content, $start_char, $i - $start_char); // now remove this template from the text being edited // if this is a partial form, establish a new insertion point if ($existing_page_content && $form_is_partial && $wgRequest->getCheck('partial')) { // if something already exists, set the new insertion point // to its position; otherwise just let it lie if (strpos($existing_page_content, $existing_template_text) !== false) { $existing_page_content = str_replace('{{{insertionpoint}}}', '', $existing_page_content); $existing_page_content = str_replace($existing_template_text, '{{{insertionpoint}}}', $existing_page_content); } } else { $existing_page_content = $this->strReplaceFirst($existing_template_text, '', $existing_page_content); } // If this is not a multiple-instance template, and we've found // a match in the source page, there's a good chance that this // page was created with this form - note that, so we don't // send the user a warning // (multiple-instance templates have a greater chance of // getting repeated from one form to the next) // - on second thought, allow even the presence of multiple- // instance templates to validate that this is the correct // form: the problem is that some forms contain *only* mutliple- // instance templates. // if (! $allow_multiple) { $source_page_matches_this_form = true; // } } } } // If the input is from the form (meaning the user has hit one // of the bottom row of buttons), and we're dealing with a // multiple template, get the values for this instance of this // template, then delete them from the array, so we can get the // next group next time - the next() command for arrays doesn't // seem to work here. if (!$source_is_page && $allow_multiple && $wgRequest) { $all_instances_printed = true; if ($old_template_name != $template_name) { $all_values_for_template = $wgRequest->getArray($query_template_name); } if ($all_values_for_template) { $cur_key = key($all_values_for_template); // skip the input coming in from the "starter" div // TODO: this code is probably no longer necessary if ($cur_key == 'num') { unset($all_values_for_template[$cur_key]); $cur_key = key($all_values_for_template); } if ($template_instance_query_values = current($all_values_for_template)) { $all_instances_printed = false; unset($all_values_for_template[$cur_key]); } } } // ===================================================== // end template processing // ===================================================== } elseif ($tag_title == 'end template') { if ($source_is_page) { // Add any unhandled template fields in the page as hidden variables. if (isset($template_contents)) { $form_text .= SFFormUtils::unhandledFieldsHTML($template_name, $template_contents); $template_contents = null; } } // Remove this tag, reset some variables, and close off form HTML tag. $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); $template_name = null; if (isset($template_label) && $curPlaceholder == null) { $form_text .= "</fieldset>\n"; unset($template_label); } $allow_multiple = false; $all_instances_printed = false; $instance_num = 0; // ===================================================== // field processing // ===================================================== } elseif ($tag_title == 'field') { $field_name = trim($tag_components[1]); $fullFieldName = $template_name . '[' . $field_name . ']'; // cycle through the other components $is_mandatory = false; $is_hidden = false; $is_restricted = false; $is_uploadable = false; $is_list = false; $input_type = null; $field_args = array(); $show_on_select = array(); $default_value = null; $values = null; $possible_values = null; $semantic_property = null; $preload_page = null; $holds_template = false; for ($i = 2; $i < count($tag_components); $i++) { $component = trim($tag_components[$i]); if ($component == 'mandatory') { $is_mandatory = true; } elseif ($component == 'hidden') { $is_hidden = true; } elseif ($component == 'restricted') { $is_restricted = !$wgUser || !$wgUser->isAllowed('editrestrictedfields'); } elseif ($component == 'list') { $is_list = true; } elseif ($component == 'edittools') { // free text only $free_text_components[] = 'edittools'; } $sub_components = array_map('trim', explode('=', $component, 2)); if (count($sub_components) == 1) { // add handling for single-value params, for custom input types $field_args[$sub_components[0]] = true; if ($component == 'holds template') { $is_hidden = true; $holds_template = true; $placeholderFields[] = self::placeholderFormat($template_name, $field_name); } } elseif (count($sub_components) == 2) { // First, set each value as its own entry in $field_args. $field_args[$sub_components[0]] = $sub_components[1]; // Then, do all special handling. if ($sub_components[0] == 'input type') { $input_type = $sub_components[1]; } elseif ($sub_components[0] == 'default') { $default_value = $wgParser->recursiveTagParse($sub_components[1]); } elseif ($sub_components[0] == 'preload') { // free text field has special handling if ($field_name == 'free text' || $field_name == '<freetext>') { $free_text_preload_page = $sub_components[1]; } else { $preload_page = $sub_components[1]; } } elseif ($sub_components[0] == 'show on select') { // html_entity_decode() is needed to turn '>' to '>' $vals = explode(';', html_entity_decode($sub_components[1])); foreach ($vals as $val) { $val = trim($val); if (empty($val)) { continue; } $option_div_pair = explode('=>', $val, 2); if (count($option_div_pair) > 1) { $option = $option_div_pair[0]; $div_id = $option_div_pair[1]; if (array_key_exists($div_id, $show_on_select)) { $show_on_select[$div_id][] = $option; } else { $show_on_select[$div_id] = array($option); } } else { $show_on_select[$val] = array(); } } } elseif ($sub_components[0] == 'autocomplete on property') { $property_name = $sub_components[1]; $propValue = SMWPropertyValue::makeUserProperty($property_name); if ($propValue->getPropertyTypeID() == '_wpg') { $field_args['autocomplete field type'] = 'relation'; } else { $field_args['autocomplete field type'] = 'attribute'; } $field_args['autocompletion source'] = $sub_components[1]; } elseif ($sub_components[0] == 'autocomplete on category') { $field_args['autocomplete field type'] = 'category'; $field_args['autocompletion source'] = $sub_components[1]; } elseif ($sub_components[0] == 'autocomplete on concept') { $field_args['autocomplete field type'] = 'concept'; $field_args['autocompletion source'] = $sub_components[1]; } elseif ($sub_components[0] == 'autocomplete on namespace') { $field_args['autocomplete field type'] = 'namespace'; $autocompletion_source = $sub_components[1]; // special handling for "main" (blank) namespace if ($autocompletion_source == "") { $autocompletion_source = "main"; } $field_args['autocompletion source'] = $autocompletion_source; } elseif ($sub_components[0] == 'autocomplete from url') { $field_args['autocomplete field type'] = 'external_url'; $field_args['autocompletion source'] = $sub_components[1]; // 'external' autocompletion is always done remotely, i.e. via API $field_args['remote autocompletion'] = true; } elseif ($sub_components[0] == 'values') { // Handle this one only after 'delimiter' has // also been set. $values = $sub_components[1]; } elseif ($sub_components[0] == 'values from property') { $propertyName = $sub_components[1]; $possible_values = SFUtils::getAllValuesForProperty($propertyName); } elseif ($sub_components[0] == 'values from category') { $category_name = ucfirst($sub_components[1]); $possible_values = SFUtils::getAllPagesForCategory($category_name, 10); } elseif ($sub_components[0] == 'values from concept') { $possible_values = SFUtils::getAllPagesForConcept($sub_components[1]); } elseif ($sub_components[0] == 'values from namespace') { $possible_values = SFUtils::getAllPagesForNamespace($sub_components[1]); } elseif ($sub_components[0] == 'values dependent on') { global $sfgDependentFields; $sfgDependentFields[] = array($sub_components[1], $fullFieldName); } elseif ($sub_components[0] == 'property') { $semantic_property = $sub_components[1]; } elseif ($sub_components[0] == 'default filename') { $default_filename = str_replace('<page name>', $page_name, $sub_components[1]); // Parse value, so default filename can include parser functions. $default_filename = $wgParser->recursiveTagParse($default_filename); $field_args['default filename'] = $default_filename; } elseif ($sub_components[0] == 'restricted') { $is_restricted = !array_intersect($wgUser->getEffectiveGroups(), array_map('trim', explode(',', $sub_components[1]))); } } } // end for // Backwards compatibility if ($input_type == 'datetime with timezone') { $input_type = 'datetime'; $field_args['include timezone'] = true; } elseif ($input_type == 'text' || $input_type == 'textarea') { // Also for backwards compatibility, // in that once b/c goes away, // this will no longer be // necessary. $field_args['no autocomplete'] = true; } if ($allow_multiple) { $field_args['part_of_multiple'] = $allow_multiple; } if (count($show_on_select) > 0) { $field_args['show on select'] = $show_on_select; } // Get the value from the request, if // it's there, and if it's not an array. $cur_value = null; $escaped_field_name = str_replace("'", "\\'", $field_name); if (isset($template_instance_query_values) && $template_instance_query_values != null && is_array($template_instance_query_values)) { // If the field name contains an // apostrophe, the array sometimes // has the apostrophe escaped, and // sometimes not. For now, just check // for both versions. // @TODO - figure this out. $field_query_val = null; if (array_key_exists($escaped_field_name, $template_instance_query_values)) { $field_query_val = $template_instance_query_values[$escaped_field_name]; } elseif (array_key_exists($field_name, $template_instance_query_values)) { $field_query_val = $template_instance_query_values[$field_name]; } if ($form_submitted || $field_query_val != '' && !is_array($field_query_val)) { $cur_value = $field_query_val; } } if (empty($cur_value) && !$form_submitted) { if (!is_null($default_value)) { // Set to the default value specified in the form, if it's there. $cur_value = $default_value; } elseif ($preload_page) { $cur_value = SFFormUtils::getPreloadedText($preload_page); } } // If the user is editing a page, and that page contains a call to // the template being processed, get the current field's value // from the template call if ($source_is_page && !empty($existing_template_text)) { if (isset($template_contents[$field_name])) { $cur_value = $template_contents[$field_name]; // If the field is a placeholder, the contents of this template // parameter should be treated as elements parsed by an another // multiple template form. // By putting that at the very end of the parsed string, we'll // have it processed as a regular multiple template form. if ($holds_template) { $existing_page_content = $existing_page_content . $cur_value; } // Now remove this value // from $template_contents, // so that at the end we // can have a list of all // the fields that weren't // handled by the form. unset($template_contents[$field_name]); } else { $cur_value = ''; } } // Handle the free text field. if ($field_name == '<freetext>') { // Add placeholders for the free text in both the form and // the page, using <free_text> tags - once all the free text // is known (at the end), it will get substituted in. if ($is_hidden) { $new_text = Html::hidden('sf_free_text', '!free_text!'); } else { $sfgTabIndex++; $sfgFieldNum++; if ($cur_value === '' || is_null($cur_value)) { $default_value = '!free_text!'; } else { $default_value = $cur_value; // If the FCKeditor extension is installed and // active, the default value needs to be parsed // for use in the editor. global $wgFCKEditorDir; if ($wgFCKEditorDir && strpos($existing_page_content, '__NORICHEDITOR__') === false) { $showFCKEditor = SFFormUtils::getShowFCKEditor(); if (!$form_submitted && $showFCKEditor & RTE_VISIBLE) { $default_value = SFFormUtils::prepareTextForFCK($cur_value); } } } $new_text = SFTextAreaInput::getHTML($default_value, 'sf_free_text', false, $form_is_disabled || $is_restricted, $field_args); if (in_array('edittools', $free_text_components)) { // borrowed from EditPage::showEditTools() $options[] = 'parse'; $edittools_text = $wgParser->recursiveTagParse(wfMsg('edittools', array('content'))); $new_text .= <<<END \t\t<div class="mw-editTools"> \t\t{$edittools_text} \t\t</div> END; } } $free_text_was_included = true; // add a similar placeholder to the data text $data_text .= "!free_text!\n"; } if ($template_name === '' || $field_name == '<freetext>') { $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); } else { if (is_array($cur_value)) { // first, check if it's a list if (array_key_exists('is_list', $cur_value) && $cur_value['is_list'] == true) { $cur_value_in_template = ""; if (array_key_exists('delimiter', $field_args)) { $delimiter = $field_args['delimiter']; } else { $delimiter = ","; } foreach ($cur_value as $key => $val) { if ($key !== "is_list") { if ($cur_value_in_template != "") { $cur_value_in_template .= $delimiter . " "; } $cur_value_in_template .= $val; } } } else { // otherwise: // if it has 1 or 2 elements, assume it's a checkbox; if it has // 3 elements, assume it's a date // - this handling will have to get more complex if other // possibilities get added if (count($cur_value) == 1) { $cur_value_in_template = SFUtils::getWordForYesOrNo(false); } elseif (count($cur_value) == 2) { $cur_value_in_template = SFUtils::getWordForYesOrNo(true); // if it's 3 or greater, assume it's a date or datetime } elseif (count($cur_value) >= 3) { $month = $cur_value['month']; $day = $cur_value['day']; if ($day !== '') { global $wgAmericanDates; if ($wgAmericanDates == false) { // pad out day to always be two digits $day = str_pad($day, 2, "0", STR_PAD_LEFT); } } $year = $cur_value['year']; $hour = $minute = $second = $ampm24h = $timezone = null; if (isset($cur_value['hour'])) { $hour = $cur_value['hour']; } if (isset($cur_value['minute'])) { $minute = $cur_value['minute']; } if (isset($cur_value['second'])) { $second = $cur_value['second']; } if (isset($cur_value['ampm24h'])) { $ampm24h = $cur_value['ampm24h']; } if (isset($cur_value['timezone'])) { $timezone = $cur_value['timezone']; } if ($month !== '' && $day !== '' && $year !== '') { // special handling for American dates - otherwise, just // the standard year/month/day (where month is a number) global $wgAmericanDates; if ($wgAmericanDates == true) { $cur_value_in_template = "{$month} {$day}, {$year}"; } else { $cur_value_in_template = "{$year}/{$month}/{$day}"; } // include whatever time information we have if (!is_null($hour)) { $cur_value_in_template .= " " . str_pad(intval(substr($hour, 0, 2)), 2, '0', STR_PAD_LEFT) . ":" . str_pad(intval(substr($minute, 0, 2)), 2, '0', STR_PAD_LEFT); } if (!is_null($second)) { $cur_value_in_template .= ":" . str_pad(intval(substr($second, 0, 2)), 2, '0', STR_PAD_LEFT); } if (!is_null($ampm24h)) { $cur_value_in_template .= " {$ampm24h}"; } if (!is_null($timezone)) { $cur_value_in_template .= " {$timezone}"; } } else { $cur_value_in_template = ""; } } } } else { // value is not an array $cur_value_in_template = $cur_value; } if ($template_name == null || $template_name === '') { $input_name = $field_name; } elseif ($allow_multiple) { // 'num' will get replaced by an actual index, either in PHP // or in Javascript, later on $input_name = $template_name . '[num][' . $field_name . ']'; $field_args['origName'] = $template_name . '[' . $field_name . ']'; } else { $input_name = $template_name . '[' . $field_name . ']'; } // If the 'values' parameter was set, separate it based on the // 'delimiter' parameter, if any. if (!empty($values)) { if (array_key_exists('delimiter', $field_args)) { $delimiter = $field_args['delimiter']; } else { $delimiter = ","; } // Remove whitespaces, and un-escape characters $possible_values = array_map('trim', explode($delimiter, $values)); $possible_values = array_map('htmlspecialchars_decode', $possible_values); } // if we're creating the page name from a formula based on // form values, see if the current input is part of that formula, // and if so, substitute in the actual value if ($form_submitted && $generated_page_name !== '') { // this line appears to be unnecessary // $generated_page_name = str_replace('.', '_', $generated_page_name); $generated_page_name = str_replace(' ', '_', $generated_page_name); $escaped_input_name = str_replace(' ', '_', $input_name); $generated_page_name = str_ireplace("<{$escaped_input_name}>", $cur_value_in_template, $generated_page_name); // once the substitution is done, replace underlines back // with spaces $generated_page_name = str_replace('_', ' ', $generated_page_name); } // disable this field if either the whole form is disabled, or // it's a restricted field and user doesn't have sysop privileges $is_disabled = $form_is_disabled || $is_restricted; // Create an SFFormField instance based on all the parameters // in the form definition, and any information from the template // definition (contained in the $all_fields parameter). $form_field = SFFormField::createFromDefinition($field_name, $input_name, $is_mandatory, $is_hidden, $is_uploadable, $possible_values, $is_disabled, $is_list, $input_type, $field_args, $all_fields, $strict_parsing); // If a property was set in the form definition, overwrite whatever // is set in the template field - this is somewhat of a hack, since // parameters set in the form definition are meant to go into the // SFFormField object, not the SFTemplateField object it contains; // it seemed like too much work, though, to create an // SFFormField::setSemanticProperty() function just for this call if ($semantic_property != null) { $form_field->template_field->setSemanticProperty($semantic_property); } $semantic_property = $form_field->template_field->getSemanticProperty(); if (!is_null($semantic_property)) { global $sfgFieldProperties; $sfgFieldProperties[$fullFieldName] = $semantic_property; } // call hooks - unfortunately this has to be split into two // separate calls, because of the different variable names in // each case if ($form_submitted) { wfRunHooks('sfCreateFormField', array(&$form_field, &$cur_value_in_template, true)); } else { wfRunHooks('sfCreateFormField', array(&$form_field, &$cur_value, false)); } // if this is not part of a 'multiple' template, increment the // global tab index (used for correct tabbing) if (!array_key_exists('part_of_multiple', $field_args)) { $sfgTabIndex++; } // increment the global field number regardless $sfgFieldNum++; // If the field is a date field, and its default value was set // to 'now', and it has no current value, set $cur_value to be // the current date. if ($default_value == 'now' && ($cur_value === '' || $cur_value == 'now')) { if ($input_type == 'date' || $input_type == 'datetime' || $input_type == 'year' || $input_type === '' && $form_field->getTemplateField()->getPropertyType() == '_dat') { // Get current time, for the time zone specified in the wiki. global $wgLocaltimezone; if (isset($wgLocaltimezone)) { $serverTimezone = date_default_timezone_get(); date_default_timezone_set($wgLocaltimezone); } $cur_time = time(); $year = date("Y", $cur_time); $month = date("n", $cur_time); $day = date("j", $cur_time); global $wgAmericanDates, $sfg24HourTime; if ($wgAmericanDates == true) { $month_names = SFFormUtils::getMonthNames(); $month_name = $month_names[$month - 1]; $cur_value_in_template = "{$month_name} {$day}, {$year}"; } else { $cur_value_in_template = "{$year}/{$month}/{$day}"; } if (isset($wgLocaltimezone)) { date_default_timezone_set($serverTimezone); } if ($input_type == 'datetime') { if ($sfg24HourTime) { $hour = str_pad(intval(substr(date("G", $cur_time), 0, 2)), 2, '0', STR_PAD_LEFT); } else { $hour = str_pad(intval(substr(date("g", $cur_time), 0, 2)), 2, '0', STR_PAD_LEFT); } $minute = str_pad(intval(substr(date("i", $cur_time), 0, 2)), 2, '0', STR_PAD_LEFT); $second = str_pad(intval(substr(date("s", $cur_time), 0, 2)), 2, '0', STR_PAD_LEFT); if ($sfg24HourTime) { $cur_value_in_template .= " {$hour}:{$minute}:{$second}"; } else { $ampm = date("A", $cur_time); $cur_value_in_template .= " {$hour}:{$minute}:{$second} {$ampm}"; } } if (array_key_exists('include timezone', $field_args)) { $timezone = date("T", $cur_time); $cur_value_in_template .= " {$timezone}"; } } } // If the field is a text field, and its default value was set // to 'current user', and it has no current value, set $cur_value // to be the current user. if ($default_value == 'current user' && ($cur_value === '' || $cur_value == 'current user')) { $cur_value_in_template = $wgUser->getName(); $cur_value = $cur_value_in_template; } // Generate a hidden field with a placeholder value that will be replaced // by the multiple-instances template output at form submission. //// <input type="hidden" value="@replace_Town___mayors@" name="Town[town_mayors]" /> if ($holds_template) { $cur_value = self::makePlaceholderInWikiText(self::placeholderFormat($template_name, $field_name)); } $new_text = $this->formFieldHTML($form_field, $cur_value); // Add a field just after the hidden field, within the HTML, to locate // where the multiple-templates HTML, stored in $multipleTemplateString, // should be inserted. if ($holds_template) { $new_text .= self::makePlaceholderInFormHTML(self::placeholderFormat($template_name, $field_name)); } // If this field is disabled, add a hidden field holding // the value of this field, because disabled inputs for some // reason don't submit their value. if ($form_field->isDisabled()) { if ($field_name == 'free text' || $field_name == '<freetext>') { $new_text .= Html::hidden('sf_free_text', '!free_text!'); } else { $new_text .= Html::hidden($input_name, $cur_value); } } if ($new_text) { // Include the field name only for non-numeric field names. if (is_numeric($field_name)) { $template_text .= "|{$cur_value_in_template}"; } else { // If the value is null, don't include it at all. if ($cur_value_in_template !== '') { $template_text .= "\n|{$field_name}={$cur_value_in_template}"; } } $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); } else { $start_position = $brackets_end_loc; } } // ===================================================== // standard input processing // ===================================================== } elseif ($tag_title == 'standard input') { // handle all the possible values $input_name = $tag_components[1]; $input_label = null; $attr = array(); // if it's a query, ignore all standard inputs except run query if ($is_query && $input_name != 'run query' || !$is_query && $input_name == 'run query') { $new_text = ""; $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); continue; } // set a flag so that the standard 'form bottom' won't get displayed $this->standardInputsIncluded = true; // cycle through the other components for ($i = 2; $i < count($tag_components); $i++) { $component = $tag_components[$i]; $sub_components = array_map('trim', explode('=', $component)); if (count($sub_components) == 1) { if ($sub_components[0] == 'edittools') { $free_text_components[] = 'edittools'; } } elseif (count($sub_components) == 2) { switch ($sub_components[0]) { case 'label': $input_label = $sub_components[1]; break; case 'class': case 'style': $attr[$sub_components[0]] = $sub_components[1]; break; } // free text input needs more handling than the rest if ($input_name == 'free text' || $input_name == '<freetext>') { if ($sub_components[0] == 'preload') { $free_text_preload_page = $sub_components[1]; } } } } if ($input_name == 'summary') { $new_text = SFFormUtils::summaryInputHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'minor edit') { $new_text = SFFormUtils::minorEditInputHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'watch') { $new_text = SFFormUtils::watchInputHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'save') { $new_text = SFFormUtils::saveButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'save and continue') { $new_text = SFFormUtils::saveAndContinueButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'preview') { $new_text = SFFormUtils::showPreviewButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'changes') { $new_text = SFFormUtils::showChangesButtonHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'cancel') { $new_text = SFFormUtils::cancelLinkHTML($form_is_disabled, $input_label, $attr); } elseif ($input_name == 'run query') { $new_text = SFFormUtils::runQueryButtonHTML($form_is_disabled, $input_label, $attr); } $section = substr_replace($section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); // ===================================================== // page info processing // ===================================================== } elseif ($tag_title == 'info') { // TODO: Generate an error message if this is included more than once foreach (array_slice($tag_components, 1) as $component) { $sub_components = array_map('trim', explode('=', $component, 2)); // Tag names are case-insensitive $tag = strtolower($sub_components[0]); if ($tag == 'create title' || $tag == 'add title') { // Handle this only if // we're adding a page. if (!$is_query && !$this->mPageTitle->exists()) { $form_page_title = $sub_components[1]; } } elseif ($tag == 'edit title') { // Handle this only if // we're editing a page. if (!$is_query && $this->mPageTitle->exists()) { $form_page_title = $sub_components[1]; } } elseif ($tag == 'query title') { // Handle this only if // we're in 'RunQuery'. if ($is_query) { $form_page_title = $sub_components[1]; } } elseif ($tag == 'partial form') { $form_is_partial = true; // replacement pages may have minimal matches... $source_page_matches_this_form = true; } elseif ($tag == 'includeonly free text' || $tag == 'onlyinclude free text') { $onlyinclude_free_text = true; } elseif ($tag == 'query form at top') { // TODO - this should be made a field of // some non-static class that actually // prints the form, instead of requiring // a global variable. global $sfgRunQueryFormAtTop; $sfgRunQueryFormAtTop = true; } } $section = substr_replace($section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc); // ===================================================== // default outer level processing // ===================================================== } else { // Tag is not one of the three allowed values - // ignore the tag. $start_position = $brackets_end_loc; } // end if } // end while if (!$all_instances_printed) { if ($template_text !== '') { // For mostly aesthetic purposes, if the template call ends with // a bunch of pipes (i.e., it's an indexed template with unused // parameters at the end), remove the pipes. $template_text = preg_replace('/\\|*$/', '', $template_text); // add another newline before the final bracket, if this template // call is already more than one line if (strpos($template_text, "\n")) { $template_text .= "\n"; } // If we're editing an existing page, and there were fields in // the template call not handled by this form, preserve those. if (!$allow_multiple) { $template_text .= SFFormUtils::addUnhandledFields($template_name); } $template_text .= "}}"; // The base $template_text will contain strings like "@replace_xxx@" // in the hidden fields when the form is submitted. // On the following loops, the text for the multiple-instance templates // is progressively reinserted in the main data, always keeping a // trailing @replace_xxx@ for a given field // The trailing @replace_xxx@ is then deleted at the end. // Note: this cleanup step could also be done with a regexp, instead of // keeping a track array (e.g., /@replace_(.*)@/) $reptmp = self::makePlaceholderInWikiText($curPlaceholder); if ($curPlaceholder != null && $data_text && strpos($data_text, $reptmp, 0) !== false) { $data_text = preg_replace('/' . $reptmp . '/', $template_text . $reptmp, $data_text); } else { $data_text .= $template_text . "\n"; } // If there is a placeholder in the // text, we know that we are // doing a replace. if ($existing_page_content && strpos($existing_page_content, '{{{insertionpoint}}}', 0) !== false) { $existing_page_content = preg_replace('/\\{\\{\\{insertionpoint\\}\\}\\}(\\r?\\n?)/', preg_replace('/\\}\\}/m', '}�', preg_replace('/\\{\\{/m', '�{', $template_text)) . "\n{{{insertionpoint}}}", $existing_page_content); // otherwise, if it's a partial form, we have to add the new // text somewhere } elseif ($form_is_partial && $wgRequest->getCheck('partial')) { $existing_page_content = preg_replace('/\\}\\}/m', '}�', preg_replace('/\\{\\{/m', '�{', $template_text)) . "\n{{{insertionpoint}}}\n" . $existing_page_content; } } } if ($allow_multiple) { if ($curPlaceholder == null) { // The normal process. $form_text .= $this->multipleTemplateInstanceHTML($form_is_disabled, $all_instances_printed, $section, $instance_num, $add_button_text); } else { // if ( $curPlaceholder != null ){ // The template text won't be appended at the end of the template like for usual multiple template forms. // The HTML text will then be stored in the $multipleTemplateString variable, // and then added in the right @insertHTML_".$placeHolderField."@"; position // Optimization: actually, instead of separating the processes, the usual multiple // template forms could also be handled this way if a fitting placeholder tag was added. $multipleTemplateString .= $this->multipleTemplateInstanceHTML($form_is_disabled, $all_instances_printed, $section, $instance_num, $add_button_text); // We replace the $multipleTemplateString HTML into the // current placeholder tag, but also add another // placeholder tag, to keep track of it. $multipleTemplateString .= self::makePlaceholderInFormHTML($curPlaceholder); if (isset($template_label)) { $multipleTemplateString .= "</fieldset>\n"; unset($template_label); } $form_text = preg_replace('/' . self::makePlaceholderInFormHTML($curPlaceholder) . '/', $multipleTemplateString, $form_text); } if (!$all_instances_printed) { // This will cause the section to be // re-parsed on the next go. $section_num--; } } else { // if ( $allow_multiple ) { $form_text .= $section; } $curPlaceholder = null; // var_dump($wgParser->getOutput()->getModules()); } // end for // Cleanup - everything has been browsed. // Remove all the remaining placeholder // tags in the HTML and wiki-text. foreach ($placeholderFields as $stringToReplace) { // remove the @<replacename>@ tags from the data that is submitted $data_text = preg_replace('/' . self::makePlaceholderInWikiText($stringToReplace) . '/', '', $data_text); // remove the @<insertHTML>@ tags from the generated HTML form $form_text = preg_replace('/' . self::makePlaceholderInFormHTML($stringToReplace) . '/', '', $form_text); } // if it wasn't included in the form definition, add the // 'free text' input as a hidden field at the bottom if (!$free_text_was_included) { $form_text .= Html::hidden('sf_free_text', '!free_text!'); } // Get free text, and add to page data, as well as retroactively // inserting it into the form. // If $form_is_partial is true then either: // (a) we're processing a replacement (param 'partial' == 1) // (b) we're sending out something to be replaced (param 'partial' is missing) if ($form_is_partial) { if (!$wgRequest->getCheck('partial')) { $free_text = $original_page_content; $form_text .= Html::hidden('partial', 1); } else { $free_text = null; $existing_page_content = preg_replace(array('/�\\{/m', '/\\}�/m'), array('{{', '}}'), $existing_page_content); $existing_page_content = preg_replace('/\\{\\{\\{insertionpoint\\}\\}\\}/', '', $existing_page_content); } } elseif ($source_is_page) { // if the page is the source, free_text will just be whatever in the // page hasn't already been inserted into the form $free_text = trim($existing_page_content); // or get it from a form submission } elseif ($wgRequest->getCheck('sf_free_text')) { $free_text = $wgRequest->getVal('sf_free_text'); if (!$free_text_was_included) { $data_text .= "!free_text!"; } // or get it from the form definition } elseif ($free_text_preload_page != null) { $free_text = SFFormUtils::getPreloadedText($free_text_preload_page); } else { $free_text = null; } if ($onlyinclude_free_text) { // modify free text and data text to insert <onlyinclude> tags $free_text = str_replace("<onlyinclude>", '', $free_text); $free_text = str_replace("</onlyinclude>", '', $free_text); $free_text = trim($free_text); $data_text = str_replace('!free_text!', '<onlyinclude>!free_text!</onlyinclude>', $data_text); } wfRunHooks('sfModifyFreeTextField', array(&$free_text, $existing_page_content)); // if the FCKeditor extension is installed, use that for the free text input global $wgFCKEditorDir; if ($wgFCKEditorDir && strpos($existing_page_content, '__NORICHEDITOR__') === false) { $showFCKEditor = SFFormUtils::getShowFCKEditor(); if (!$form_submitted && $showFCKEditor & RTE_VISIBLE) { $free_text = SFFormUtils::prepareTextForFCK($free_text); } } else { $showFCKEditor = 0; } // now that we have it, substitute free text into the form and page $escaped_free_text = Sanitizer::safeEncodeAttribute($free_text); $form_text = str_replace('!free_text!', $escaped_free_text, $form_text); $data_text = str_replace('!free_text!', $free_text, $data_text); // Add a warning in, if we're editing an existing page and that // page appears to not have been created with this form. if (!$is_query && $this->mPageTitle->exists() && $existing_page_content !== '' && !$source_page_matches_this_form) { $form_text = "\t" . '<div class="warningbox">' . wfMsg('sf_formedit_formwarning', $this->mPageTitle->getFullURL()) . "</div>\n<br clear=\"both\" />\n" . $form_text; } // add form bottom, if no custom "standard inputs" have been defined if (!$this->standardInputsIncluded) { if ($is_query) { $form_text .= SFFormUtils::queryFormBottom($form_is_disabled); } else { $form_text .= SFFormUtils::formBottom($form_is_disabled); } } if (!$is_query) { $form_text .= Html::hidden('wpStarttime', wfTimestampNow()); $article = new Article($this->mPageTitle, 0); $form_text .= Html::hidden('wpEdittime', $article->getTimestamp()); } $form_text .= "\t</form>\n"; // Add general Javascript code. wfRunHooks('sfAddJavascriptToForm', array(&$javascript_text)); // @TODO The FCKeditor Javascript should be handled within // the FCKeditor extension itself, using the hook. $javascript_text = ""; if ($free_text_was_included && $showFCKEditor > 0) { $javascript_text .= SFFormUtils::mainFCKJavascript($showFCKEditor, $field_args); if ($showFCKEditor & (RTE_TOGGLE_LINK | RTE_POPUP)) { $javascript_text .= SFFormUTils::FCKToggleJavascript(); } if ($showFCKEditor & RTE_POPUP) { $javascript_text .= SFFormUTils::FCKPopupJavascript(); } } // Send the autocomplete values to the browser, along with the // mappings of which values should apply to which fields. // If doing a replace, the data text is actually the modified original page if ($wgRequest->getCheck('partial')) { $data_text = $existing_page_content; } if (!$is_embedded) { $form_page_title = $wgParser->recursiveTagParse(str_replace("{{!}}", "|", $form_page_title)); } else { $form_page_title = null; } // If the form has already been submitted, i.e. this is just // the redirect page, get rid of all the Javascript, to avoid // JS errors. if ($form_submitted) { $javascript_text = ''; } $parserOutput = $wgParser->getOutput(); $wgOut->addParserOutputNoText($parserOutput); // $wgParser = $oldParser; wfProfileOut(__METHOD__); return array($form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name); }
protected function appendGeneralInfo($property) { global $wgContLang; $config = $this->getConfig(); $data = array(); $mainPage = Title::newMainPage(); $data['mainpage'] = $mainPage->getPrefixedText(); $data['base'] = wfExpandUrl($mainPage->getFullURL(), PROTO_CURRENT); $data['sitename'] = $config->get('Sitename'); // wgLogo can either be a relative or an absolute path // make sure we always return an absolute path $data['logo'] = wfExpandUrl($config->get('Logo'), PROTO_RELATIVE); $data['generator'] = "MediaWiki {$config->get('Version')}"; $data['phpversion'] = PHP_VERSION; $data['phpsapi'] = PHP_SAPI; if (defined('HHVM_VERSION')) { $data['hhvmversion'] = HHVM_VERSION; } $data['dbtype'] = $config->get('DBtype'); $data['dbversion'] = $this->getDB()->getServerVersion(); $allowFrom = array(''); $allowException = true; if (!$config->get('AllowExternalImages')) { $data['imagewhitelistenabled'] = (bool) $config->get('EnableImageWhitelist'); $allowFrom = $config->get('AllowExternalImagesFrom'); $allowException = !empty($allowFrom); } if ($allowException) { $data['externalimages'] = (array) $allowFrom; ApiResult::setIndexedTagName($data['externalimages'], 'prefix'); } $data['langconversion'] = !$config->get('DisableLangConversion'); $data['titleconversion'] = !$config->get('DisableTitleConversion'); if ($wgContLang->linkPrefixExtension()) { $linkPrefixCharset = $wgContLang->linkPrefixCharset(); $data['linkprefixcharset'] = $linkPrefixCharset; // For backwards compatibility $data['linkprefix'] = "/^((?>.*[^{$linkPrefixCharset}]|))(.+)\$/sDu"; } else { $data['linkprefixcharset'] = ''; $data['linkprefix'] = ''; } $linktrail = $wgContLang->linkTrail(); $data['linktrail'] = $linktrail ?: ''; $data['legaltitlechars'] = Title::legalChars(); global $IP; $git = SpecialVersion::getGitHeadSha1($IP); if ($git) { $data['git-hash'] = $git; $data['git-branch'] = SpecialVersion::getGitCurrentBranch($GLOBALS['IP']); } else { $svn = SpecialVersion::getSvnRevision($IP); if ($svn) { $data['rev'] = $svn; } } // 'case-insensitive' option is reserved for future $data['case'] = $config->get('CapitalLinks') ? 'first-letter' : 'case-sensitive'; $data['lang'] = $config->get('LanguageCode'); $fallbacks = array(); foreach ($wgContLang->getFallbackLanguages() as $code) { $fallbacks[] = array('code' => $code); } $data['fallback'] = $fallbacks; ApiResult::setIndexedTagName($data['fallback'], 'lang'); if ($wgContLang->hasVariants()) { $variants = array(); foreach ($wgContLang->getVariants() as $code) { $variants[] = array('code' => $code, 'name' => $wgContLang->getVariantname($code)); } $data['variants'] = $variants; ApiResult::setIndexedTagName($data['variants'], 'lang'); } $data['rtl'] = $wgContLang->isRTL(); $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding(); $data['readonly'] = wfReadOnly(); if ($data['readonly']) { $data['readonlyreason'] = wfReadOnlyReason(); } $data['writeapi'] = (bool) $config->get('EnableWriteAPI'); $tz = $config->get('Localtimezone'); $offset = $config->get('LocalTZoffset'); if (is_null($tz)) { $tz = 'UTC'; $offset = 0; } elseif (is_null($offset)) { $offset = 0; } $data['timezone'] = $tz; $data['timeoffset'] = intval($offset); $data['articlepath'] = $config->get('ArticlePath'); $data['scriptpath'] = $config->get('ScriptPath'); $data['script'] = $config->get('Script'); $data['variantarticlepath'] = $config->get('VariantArticlePath'); $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath'; $data['server'] = $config->get('Server'); $data['servername'] = $config->get('ServerName'); $data['wikiid'] = wfWikiID(); $data['time'] = wfTimestamp(TS_ISO_8601, time()); $data['misermode'] = (bool) $config->get('MiserMode'); $data['maxuploadsize'] = UploadBase::getMaxUploadSize(); $data['minuploadchunksize'] = (int) $this->getConfig()->get('MinUploadChunkSize'); $data['thumblimits'] = $config->get('ThumbLimits'); ApiResult::setArrayType($data['thumblimits'], 'BCassoc'); ApiResult::setIndexedTagName($data['thumblimits'], 'limit'); $data['imagelimits'] = array(); ApiResult::setArrayType($data['imagelimits'], 'BCassoc'); ApiResult::setIndexedTagName($data['imagelimits'], 'limit'); foreach ($config->get('ImageLimits') as $k => $limit) { $data['imagelimits'][$k] = array('width' => $limit[0], 'height' => $limit[1]); } $favicon = $config->get('Favicon'); if (!empty($favicon)) { // wgFavicon can either be a relative or an absolute path // make sure we always return an absolute path $data['favicon'] = wfExpandUrl($favicon, PROTO_RELATIVE); } Hooks::run('APIQuerySiteInfoGeneralInfo', array($this, &$data)); return $this->getResult()->addValue('query', $property, $data); }
public function __construct() { parent::__construct('readonly', 'readonlytext', wfReadOnlyReason()); }
function execute($subpage) { global $wgUser; $this->setHeaders(); if (!$this->userCanExecute($wgUser)) { $this->getOutput()->addWikiMsg('centralauth-merge-denied'); $this->getOutput()->addWikiMsg('centralauth-readmore-text'); return; } if (!$this->getUser()->isLoggedIn()) { $loginpage = SpecialPage::getTitleFor('Userlogin'); $loginurl = $loginpage->getFullUrl(array('returnto' => $this->getTitle()->getPrefixedText())); $this->getOutput()->addWikiMsg('centralauth-merge-notlogged', $loginurl); $this->getOutput()->addWikiMsg('centralauth-readmore-text'); return; } if (wfReadOnly()) { $this->getOutput()->setPagetitle(wfMsg('readonly')); $this->getOutput()->addWikiMsg('readonlytext', wfReadOnlyReason()); return; } $this->mUserName = $this->getUser()->getName(); $this->mAttemptMerge = $this->getRequest()->wasPosted(); $this->mMergeAction = $this->getRequest()->getVal('wpMergeAction'); $this->mPassword = $this->getRequest()->getVal('wpPassword'); $this->mWikiIDs = $this->getRequest()->getArray('wpWikis'); $this->mSessionToken = $this->getRequest()->getVal('wpMergeSessionToken'); $this->mSessionKey = pack("H*", $this->getRequest()->getVal('wpMergeSessionKey')); // Possible demo states // success, all accounts merged // successful login, some accounts merged, others left // successful login, others left // not account owner, others left // is owner / is not owner // did / did not merge some accounts // do / don't have more accounts to merge if ($this->mAttemptMerge) { switch ($this->mMergeAction) { case "dryrun": $this->doDryRunMerge(); case "initial": $this->doInitialMerge(); case "cleanup": $this->doCleanupMerge(); case "attach": $this->doAttachMerge(); case "remove": $this->doUnattach(); default: $this->invalidAction(); } return; } $globalUser = new CentralAuthUser($this->mUserName); if ($globalUser->exists()) { if ($globalUser->isAttached()) { $this->showCleanupForm(); } else { $this->showAttachForm(); } } else { $this->showWelcomeForm(); } }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param array $limit set of restriction keys * @param array $expiry per restriction type expiration * @param int &$cascade Set to false if cascading protection isn't allowed. * @param string $reason * @param User $user The user updating the restrictions * @return Status */ public function doUpdateRestrictions( array $limit, array $expiry, &$cascade, $reason, User $user ) { global $wgCascadingRestrictionLevels; if ( wfReadOnly() ) { return Status::newFatal( 'readonlytext', wfReadOnlyReason() ); } $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->getId(); if ( !$cascade ) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); // @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); // we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB( DB_MASTER ); foreach ( $restrictionTypes as $action ) { if ( !isset( $expiry[$action] ) ) { $expiry[$action] = $dbw->getInfinity(); } if ( !isset( $limit[$action] ) ) { $limit[$action] = ''; } elseif ( $limit[$action] != '' ) { $protect = true; } // Get current restrictions on $action $current = implode( '', $this->mTitle->getRestrictions( $action ) ); if ( $current != '' ) { $isProtected = true; } if ( $limit[$action] != $current ) { $changed = true; } elseif ( $limit[$action] != '' ) { // Only check expiry change if the action is actually being // protected, since expiry does nothing on an not-protected // action. if ( $this->mTitle->getRestrictionExpiry( $action ) != $expiry[$action] ) { $changed = true; } } } if ( !$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade ) { $changed = true; } // If nothing has changed, do nothing if ( !$changed ) { return Status::newGood(); } if ( !$protect ) { // No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ( $isProtected ) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } if ( $id ) { // Protection of existing page if ( !wfRunHooks( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) { return Status::newGood(); } // Only certain restrictions can cascade... $editrestriction = isset( $limit['edit'] ) ? array( $limit['edit'] ) : $this->mTitle->getRestrictions( 'edit' ); foreach ( array_keys( $editrestriction, 'sysop' ) as $key ) { $editrestriction[$key] = 'editprotected'; // backwards compatibility } foreach ( array_keys( $editrestriction, 'autoconfirmed' ) as $key ) { $editrestriction[$key] = 'editsemiprotected'; // backwards compatibility } $cascadingRestrictionLevels = $wgCascadingRestrictionLevels; foreach ( array_keys( $cascadingRestrictionLevels, 'sysop' ) as $key ) { $cascadingRestrictionLevels[$key] = 'editprotected'; // backwards compatibility } foreach ( array_keys( $cascadingRestrictionLevels, 'autoconfirmed' ) as $key ) { $cascadingRestrictionLevels[$key] = 'editsemiprotected'; // backwards compatibility } // The schema allows multiple restrictions if ( !array_intersect( $editrestriction, $cascadingRestrictionLevels ) ) { $cascade = false; } // insert null revision to identify the page protection change as edit summary $latest = $this->getLatest(); $nullRevision = $this->insertProtectNullRevision( $revCommentMsg, $limit, $expiry, $cascade, $reason ); if ( $nullRevision === null ) { return Status::newFatal( 'no-null-revision', $this->mTitle->getPrefixedText() ); } // Update restrictions table foreach ( $limit as $action => $restrictions ) { if ( $restrictions != '' ) { $dbw->replace( 'page_restrictions', array( array( 'pr_page', 'pr_type' ) ), array( 'pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => ( $cascade && $action == 'edit' ) ? 1 : 0, 'pr_expiry' => $dbw->encodeExpiry( $expiry[$action] ) ), __METHOD__ ); } else { $dbw->delete( 'page_restrictions', array( 'pr_page' => $id, 'pr_type' => $action ), __METHOD__ ); } } // Clear out legacy restriction fields $dbw->update( 'page', array( 'page_restrictions' => '' ), array( 'page_id' => $id ), __METHOD__ ); wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) ); wfRunHooks( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) ); } else { // Protection of non-existing page (also known as "title protection") // Cascade protection is meaningless in this case $cascade = false; if ( $limit['create'] != '' ) { $dbw->replace( 'protected_titles', array( array( 'pt_namespace', 'pt_title' ) ), array( 'pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->encodeExpiry( wfTimestampNow() ), 'pt_expiry' => $dbw->encodeExpiry( $expiry['create'] ), 'pt_user' => $user->getId(), 'pt_reason' => $reason, ), __METHOD__ ); } else { $dbw->delete( 'protected_titles', array( 'pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey() ), __METHOD__ ); } } $this->mTitle->flushRestrictions(); InfoAction::invalidateCache( $this->mTitle ); if ( $logAction == 'unprotect' ) { $params = array(); } else { $protectDescriptionLog = $this->protectDescriptionLog( $limit, $expiry ); $params = array( $protectDescriptionLog, $cascade ? 'cascade' : '' ); } // Update the protection log $log = new LogPage( 'protect' ); $log->addEntry( $logAction, $this->mTitle, trim( $reason ), $params, $user ); return Status::newGood(); }
echo $ajaxLoginComponent; ?> </div> <?php if ($wgUser->isAllowed('createaccount')) { ?> <div id="AjaxLoginRegisterForm" <?php echo $showRegister ? '' : 'style="display:none"'; ?> title="<?php print wfMsg('login'); ?> "> <?php if (!$isReadOnly) { echo $registerAjax; } else { // RT #85688 ?> <div id="AjaxLoginReadOnlyMessage"><?php echo wfMsg('comboajaxlogin-readonlytext', wfReadOnlyReason()); ?> </div> <?php } ?> </div><?php } ?> </div>