License for SkywikiMagic

SkywikiMagic/README.md0000644000000000000000000000014214723367061013434 0ustar  rootroot# WikiOasisMagic

Forked from [miraheze/MirahezeMagic](https://github.com/miraheze/MirahezeMagic)
SkywikiMagic/extension.json0000644000000000000000000000451214727376305015076 0ustar  rootroot{
	"name": "SkywikiMagic",
	"author": [
		"Agent Isai",
		"John Lewis",
		"Labster",
		"MacFan4000",
		"Reception123",
		"Revi",
		"Paladox",
		"Southparkfan",
		"Universal Omega",
		"Waki285"
	],
	"descriptionmsg": "skywikimagic-description",
	"namemsg": "skywikimagic-extensionname",
	"license-name": "GPL-3.0-or-later",
	"type": "other",
	"requires": {
		"MediaWiki": ">= 1.42.0",
		"platform": {
			"php": ">= 8.0"
		}
	},
	"MessagesDirs": {
		"WikiOasisMagic": [
			"i18n/wikioasis"
		]
	},
	"AutoloadNamespaces": {
		"WikiOasis\\WikiOasisMagic\\": "includes/"
	},
	"SpecialPages": {
		"CreateNewWiki": {
			"class": "WikiOasis\\WikiOasisMagic\\SpecialCreateNewWiki",
			"services": [
				"CreateWikiDatabaseUtils",
				"WikiManagerFactory"
			]
		},
                "ChangeDomain": {
                        "class": "WikiOasis\\WikiOasisMagic\\SpecialChangeDomain",
                        "services": [
                                "CreateWikiDatabaseUtils",
                                "RemoteWikiFactory"
                        ]
                }
	},
	"AvailableRights": [
		"createnewwiki"
	],
	"Hooks": {
		"AbuseFilterShouldFilterAction": {
			"handler": "Main"
		},
		"ContributionsToolLinks": {
			"handler": "Main"
		},
		"CreateWikiStatePrivate": {
			"handler": "Main"
		},
		"CreateWikiTables": {
			"handler": "Main"
		},
		"GetLocalURL::Internal": {
			"handler": "Main"
		},
		"GlobalUserPageWikis": {
			"handler": "Main"
		},
        "ImportDumpJobGetFile": {
			"handler": "Main"
		},
		"MessageCacheFetchOverrides": {
			"handler": "Main"
		},
		"MimeMagicInit": {
			"handler": "Main"
		},
		"SiteNoticeAfter": {
			"handler": "Main"
		},
		"SkinAddFooterLinks": {
			"handler": "Main"
		},
		"TitleReadWhitelist": {
			"handler": "Main"
		}
	},
	"HookHandlers": {
		"Main": {
			"class": "WikiOasis\\WikiOasisMagic\\HookHandlers\\Main",
			"factory": "WikiOasis\\WikiOasisMagic\\HookHandlers\\Main::factory",
			"services": [
				"MainConfig",
				"CommentStore",
				"DBLoadBalancerFactory",
				"HttpRequestFactory"
			]
		}
	},
	"config": {
		"WikiOasisMagicMemcachedServers": {
			"description": "Array. Memcached servers to use for clearing memcached keys when a wiki is deleted or renamed.",
			"value": []
		}
	},
	"ConfigRegistry": {
		"WikiOasisMagic": "MediaWiki\\Config\\GlobalVarConfig::newInstance"
	},
	"manifest_version": 2
}
SkywikiMagic/i18n/0000755000000000000000000000000014723367061012737 5ustar  rootrootSkywikiMagic/i18n/wikioasis/0000755000000000000000000000000014727377257014755 5ustar  rootrootSkywikiMagic/i18n/wikioasis/en.json0000644000000000000000000001401314727377257016251 0ustar  rootroot{
	"@metadata": {
		"authors": [
			"Agent Isai",
			"John Lewis",
			"AlvaroMolina",
			"MacFan4000",
			"Universal Omega",
			"Waki285"
		]
	},
    "skywikimagic-extensionname": "SkywikiMagic",
    "skywikimagic-description": "SkyWiki dedicated extension",
	"extensions-antispam": "Spam prevention",
	"extensions-api": "API",
	"extensions-editors": "Editors",
	"extensions-mediahandlers": "Media handlers",
	"extensions-parserhooks": "Parser hooks",
	"extensions-skins": "Skins",
	"extensions-specialpages": "Special pages",
	"extensions-variable": "Variables",
	"grant-usedatadumpapi": "Create, view, and delete dumps",
	"group-autopatrolled-member": "{{GENDER:$1|autopatrolled}}",
	"group-autopatrolled": "Autopatrolled users",
	"group-confirmed-member": "{{GENDER:$1|confirmed user}}",
	"group-confirmed": "Confirmed users",
	"group-electionadmin": "Election administrators",
	"group-electionadmin-member": "{{GENDER:$1|election administrator}}",
	"group-flood-member": "{{GENDER:$1|flooder}}",
	"group-flood": "Flooders",
	"group-founder": "Founders",
	"group-founder-member": "{{GENDER:$1|founder}}",
	"group-global-admin-member": "{{GENDER:$1|global administrator}}",
	"group-global-admin": "Global Administrators",
	"group-global-flood-member": "{{GENDER:$1|global flooder}}",
	"group-global-flood": "Global flooders",
	"group-global-ipblock-exempt-member": "{{GENDER:$1|global IP block exempt}}",
	"group-global-ipblock-exempt": "Global IP block exemption",
	"group-global-patroller-member": "{{GENDER:$1|global patroller}}",
	"group-global-patroller": "Global patrollers",
	"group-global-renamer-member": "{{GENDER:$1|global renamer}}",
	"group-global-renamer": "Global renamers",
	"group-global-rollbacker-member": "{{GENDER:$1|global rollbacker}}",
	"group-global-rollbacker": "Global rollbackers",
	"group-ipblock-exempt-member": "{{GENDER:$1|IP block exempt}}",
	"group-ipblock-exempt": "IP block exemption",
	"group-member": "Members",
	"group-member-member": "{{GENDER:$1|member}}",
	"group-patroller-member": "{{GENDER:$1|patroller}}",
	"group-patroller": "Patrollers",
	"group-rollbacker-member": "{{GENDER:$1|rollbacker}}",
	"group-rollbacker": "Rollbackers",
	"group-steward-member": "{{GENDER:$1|steward}}",
	"group-steward": "Stewards",
    "group-sysadmin-member": "{{GENDER:$1|system administrator}}",
    "group-sysadmin": "System administrators",
	"group-translator-member": "{{GENDER:$1|translator}}",
	"group-translator": "Translators",
	"group-trustandsafety-member": "{{GENDER:$1|Trust and Safety member}}",
	"group-trustandsafety": "Trust and Safety",
	"group-wiki-creator-member": "{{GENDER:$1|wiki creator}}",
	"group-wiki-creator": "Wiki creators",
	"grouppage-autopatrolled": "wom:Special:MyLanguage/User groups#{{int:Group-autopatrolled}}",
	"grouppage-confirmed": "wom:Special:MyLanguage/User groups#{{int:Group-autoconfirmed}}",
	"grouppage-electionadmin": "wom:Special:MyLanguage/Meta:Election administrators",
	"grouppage-flood": "wom:Special:MyLanguage/User groups#{{int:Group-flood}}",
	"grouppage-founder": "wom:Special:MyLanguage/User groups#{{int:Group-founder}}",
	"grouppage-global-admin": "wom:Special:MyLanguage/Global Administrators",
	"grouppage-global-flood": "wom:Special:MyLanguage/Global flooders",
	"grouppage-global-ipblock-exempt": "wom:Special:MyLanguage/Global IP block exemption",
	"grouppage-global-patroller": "wom:Special:MyLanguage/Global Patrollers",
	"grouppage-global-renamer": "wom:Special:MyLanguage/Global renamers",
	"grouppage-global-rollbacker": "wom:Special:MyLanguage/Global rollbackers",
	"grouppage-ipblock-exempt": "wom:Special:MyLanguage/User groups#{{int:Group-ipblock-exempt}}",
	"grouppage-member": "wom:Special:MyLanguage/User groups#{{int:Group-member}}",
	"grouppage-patroller": "wom:Special:MyLanguage/User groups#{{int:Group-patroller}}",
	"grouppage-rollbacker": "wom:Special:MyLanguage/User groups#{{int:Group-rollbacker}}",
	"grouppage-steward": "wom:Special:MyLanguage/Stewards",
    "grouppage-sysadmin": "wom:Special:MyLanguage/System administrators",
	"grouppage-trustandsafety": "wom:Special:MyLanguage/Trust and Safety",
	"grouppage-wiki-creator": "wom:Special:MyLanguage/Meta:Wiki creators",
	"settings-anti-spam": "Anti Spam",
	"settings-beta": "Beta",
	"settings-categories": "Categories",
	"settings-discussion": "Discussion",
	"settings-editing": "Editing",
	"settings-links": "Links",
	"settings-localisation": "Localisation",
	"settings-maps": "Maps",
	"settings-media": "Media",
	"settings-notifications": "Notifications",
	"settings-parserfunctions": "Parser Functions",
	"settings-permissions": "Permissions",
	"settings-preferences": "Preferences",
	"settings-recentchanges": "Recent changes",
	"settings-restricted": "Restricted",
	"settings-seo": "SEO",
	"settings-socialtools": "Social tools",
	"settings-styling": "Styling",
	"settings-wikibase": "Wikibase",
    "specialpages-group-wikimanage": "Wiki management",
	"miraheze-label-managewiki-article-path": "Article path",
	"miraheze-label-managewiki-article-path-root": "Don't use /wiki/ for articles (use the root path)",
	"miraheze-label-managewiki-article-path-wiki": "Use /wiki/ for articles",
	"miraheze-label-managewiki-mainpage-is-domain-root": "Make the main page of this wiki use the domain root?",
	"miraheze-label-managewiki-mediawiki-version": "MediaWiki version",
	"miraheze-label-managewiki-primary-domain": "Primary domain",
    "createnewwiki": "Start your own community",
    "createnewwiki-description": "Every wiki, whether big or small, needs an address and a name. Please note that the subdomain can only contain alphanumeric characters.",
        "action-createnewwiki": "create a new wiki through CreateNewWiki",
        "right-createnewwiki": "Create a new wiki through CreateNewWiki",
        "createnewwiki-label-subdomain": "Subdomain:",
        "createnewwiki-placeholder-subdomain": "Give your community a subdomain",
        "createnewwiki-placeholder-sitename": "Name your wiki",
        "changedomain": "Change domain",
	"changedomain-info": "Insert the database name of the wiki you wish to change the domain for.",
	"changedomain-label-domain": "Domain"
}
SkywikiMagic/includes/0000755000000000000000000000000014727411650013764 5ustar  rootrootSkywikiMagic/includes/SpecialCreateNewWiki.php0000644000000000000000000001105314727376352020510 0ustar  rootroot<?php

namespace WikiOasis\WikiOasisMagic;

use ErrorPageError;
use MediaWiki\Html\Html;
use MediaWiki\Message\Message;
use MediaWiki\SpecialPage\FormSpecialPage;
use Miraheze\CreateWiki\ConfigNames;
use Miraheze\CreateWiki\Services\CreateWikiDatabaseUtils;
use Miraheze\CreateWiki\Services\WikiManagerFactory;
use OOUI;

class SpecialCreateNewWiki extends FormSpecialPage {

	private CreateWikiDatabaseUtils $databaseUtils;
	private WikiManagerFactory $wikiManagerFactory;

	public function __construct(
		CreateWikiDatabaseUtils $databaseUtils,
		WikiManagerFactory $wikiManagerFactory
	) {
		parent::__construct( 'CreateNewWiki', 'createnewwiki' );

		$this->databaseUtils = $databaseUtils;
		$this->wikiManagerFactory = $wikiManagerFactory;
	}

	/**
	 * @param ?string $par
	 */
	public function execute( $par ): void {
		if ( !$this->databaseUtils->isCurrentWikiCentral() ) {
			throw new ErrorPageError( 'errorpagetitle', 'createwiki-wikinotcentralwiki' );
		}

		if ( !$this->getUser()->isEmailConfirmed() ) {
			throw new ErrorPageError( 'requestwiki', 'requestwiki-error-emailnotconfirmed' );
		}

		parent::execute( $par );
	}

	/**
	 * @inheritDoc
	 */
	protected function getFormFields(): array {
		$formDescriptor = [
			'dbname' => [
				#'label-message' => 'createnewwiki-label-subdomain',
				'label' => "." . $this->getConfig()->get( 'CreateWikiSubdomain' ),
				'cssclass' => 'subdomain',
				'placeholder-message' => 'createnewwiki-placeholder-subdomain',
				'type' => 'text',
				'required' => true,
				'validation-callback' => [ $this, 'isValidDatabase' ],
			],
			'sitename' => [
				'label-message' => 'createwiki-label-sitename',
				'placeholder-message' => 'createnewwiki-placeholder-sitename',
				'type' => 'text',
				'size' => 20,
			],
			'language' => [
				'type' => 'language',
				'label-message' => 'createwiki-label-language',
				'default' => 'en',
			],
		];

		if ( $this->getConfig()->get( ConfigNames::UsePrivateWikis ) ) {
			$formDescriptor['private'] = [
				'type' => 'check',
				'label-message' => 'createwiki-label-private',
			];
		}

		if ( $this->getConfig()->get( ConfigNames::Categories ) ) {
			$formDescriptor['category'] = [
				'type' => 'select',
				'label-message' => 'createwiki-label-category',
				'options' => $this->getConfig()->get( ConfigNames::Categories ),
				'default' => 'uncategorised',
			];
		}

		$formDescriptor['reason'] = [
			'type' => 'textarea',
			'rows' => 10,
			'label-message' => 'createwiki-label-reason',
			'help-message' => 'createwiki-help-reason',
			'required' => true,
			'useeditfont' => true,
		];

		return $formDescriptor;
	}

	/**
	 * @inheritDoc
	 */
	public function onSubmit( array $formData ): bool {
		if ( $this->getConfig()->get( ConfigNames::UsePrivateWikis ) ) {
			$private = $formData['private'];
		} else {
			$private = 0;
		}

		if ( $this->getConfig()->get( ConfigNames::Categories ) ) {
			$category = $formData['category'];
		} else {
			$category = 'uncategorised';
		}

		$wikiManager = $this->wikiManagerFactory->newInstance( $formData['dbname'] . 'wiki' );
		$wikiManager->create(
			sitename: $formData['sitename'],
			language: $formData['language'],
			private: $private,
			category: $category,
			requester: $this->getContext()->getUser()->getName(),
			actor: $this->getContext()->getUser()->getName(),
			reason: $formData['reason'],
			extra: []
		);

		$this->getOutput()->redirect( "http://" . $formData['dbname'] . "." . $this->getConfig()->get( 'CreateWikiSubdomain' ) ); 

		return true;
	}

	public function isValidDatabase( ?string $dbname ): bool|string|Message {
		if ( !$dbname || ctype_space( $dbname ) ) {
			return $this->msg( 'htmlform-required' );
		}

		$wikiManager = $this->wikiManagerFactory->newInstance( $dbname . 'wiki' );
		$check = $wikiManager->checkDatabaseName( $dbname . 'wiki', forRename: false );

		if ( $check ) {
			// Will return a string — the error it received
			return $check;
		}

		return true;
	}

	/**
	 * @inheritDoc
	 */
	protected function getDisplayFormat(): string {
		return 'ooui';
	}

	/**
	 * @inheritDoc
	 */
	protected function getGroupName(): string {
		return 'wikimanage';
	}

	/**
	 * @inheritDoc
	 */
	protected function preHtml(): string {
		return $this->msg( 'createnewwiki-description' ) . "
			<style>
				.subdomain .oo-ui-fieldLayout-body {
					display: flex;
					flex-direction: row-reverse;
					justify-content: flex-end;
				}
				.subdomain .oo-ui-fieldLayout-field {
					flex: 1;
					max-width: 50em;
					margin-right: 1rem;
				}
				.oo-ui-fieldLayout-body .oo-ui-iconElement-icon {
					margin-right: .25rem;
				}
			</style>
		";
	}
}
SkywikiMagic/includes/HookHandlers/0000755000000000000000000000000014727360362016350 5ustar  rootrootSkywikiMagic/includes/HookHandlers/Main.php0000644000000000000000000004016214727234344017750 0ustar  rootroot<?php

namespace WikiOasis\WikiOasisMagic\HookHandlers;

use MediaWiki\Cache\Hook\MessageCacheFetchOverridesHook;
use MediaWiki\CommentStore\CommentStore;
use MediaWiki\Config\Config;
use MediaWiki\Config\GlobalVarConfig;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Context\RequestContext;
use MediaWiki\Extension\AbuseFilter\AbuseFilterServices;
use MediaWiki\Extension\AbuseFilter\Hooks\AbuseFilterShouldFilterActionHook;
use MediaWiki\Extension\AbuseFilter\Variables\VariableHolder;
use MediaWiki\Extension\CentralAuth\User\CentralAuthUser;
use MediaWiki\Hook\ContributionsToolLinksHook;
use MediaWiki\Hook\GetLocalURL__InternalHook;
use MediaWiki\Hook\MimeMagicInitHook;
use MediaWiki\Hook\SiteNoticeAfterHook;
use MediaWiki\Hook\SkinAddFooterLinksHook;
use MediaWiki\Html\Html;
use MediaWiki\Http\HttpRequestFactory;
use MediaWiki\Linker\Linker;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\Hook\TitleReadWhitelistHook;
use MediaWiki\Shell\Shell;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Title\Title;
use MediaWiki\User\User;
use MediaWiki\WikiMap\WikiMap;
use Memcached;
use MessageCache;
use Miraheze\CreateWiki\Hooks\CreateWikiStatePrivateHook;
use Miraheze\CreateWiki\Hooks\CreateWikiTablesHook;
use Miraheze\ManageWiki\Helpers\ManageWikiExtensions;
use Miraheze\ManageWiki\Helpers\ManageWikiSettings;
use Miraheze\ImportDump\Hooks\ImportDumpJobGetFileHook;
use Redis;
use Skin;
use Throwable;
use Wikimedia\IPUtils;
use Wikimedia\Rdbms\DBConnRef;
use Wikimedia\Rdbms\ILBFactory;

class Main implements
	AbuseFilterShouldFilterActionHook,
	ContributionsToolLinksHook,
	CreateWikiStatePrivateHook,
	CreateWikiTablesHook,
	GetLocalURL__InternalHook,
    ImportDumpJobGetFileHook,
	MessageCacheFetchOverridesHook,
	MimeMagicInitHook,
	SiteNoticeAfterHook,
	SkinAddFooterLinksHook,
	TitleReadWhitelistHook
{

	/** @var ServiceOptions */
	private $options;

	/** @var CommentStore */
	private $commentStore;

	/** @var ILBFactory */
	private $dbLoadBalancerFactory;

	/** @var HttpRequestFactory */
	private $httpRequestFactory;

	/**
	 * @param ServiceOptions $options
	 * @param CommentStore $commentStore
	 * @param ILBFactory $dbLoadBalancerFactory
	 * @param HttpRequestFactory $httpRequestFactory
	 */
	public function __construct(
		ServiceOptions $options,
		CommentStore $commentStore,
		ILBFactory $dbLoadBalancerFactory,
		HttpRequestFactory $httpRequestFactory
	) {
		$this->options = $options;
		$this->commentStore = $commentStore;
		$this->dbLoadBalancerFactory = $dbLoadBalancerFactory;
		$this->httpRequestFactory = $httpRequestFactory;
	}

	/**
	 * @param Config $mainConfig
	 * @param CommentStore $commentStore
	 * @param ILBFactory $dbLoadBalancerFactory
	 * @param HttpRequestFactory $httpRequestFactory
	 *
	 * @return self
	 */
	public static function factory(
		Config $mainConfig,
		CommentStore $commentStore,
		ILBFactory $dbLoadBalancerFactory,
		HttpRequestFactory $httpRequestFactory
	): self {
		return new self(
			new ServiceOptions(
				[
					'ArticlePath',
					'CreateWikiCacheDirectory',
					'CreateWikiGlobalWiki',
					'EchoSharedTrackingDB',
					'JobTypeConf',
					'LanguageCode',
					'LocalDatabases',
					'ManageWikiSettings',
					'WikiOasisMagicMemcachedServers',
					'Script',
				],
				$mainConfig
			),
			$commentStore,
			$dbLoadBalancerFactory,
			$httpRequestFactory
		);
	}

	/**
	 * Avoid filtering automatic account creation
	 *
	 * @param VariableHolder $vars
	 * @param Title $title
	 * @param User $user
	 * @param array &$skipReasons
	 * @return bool|void
	 */
	public function onAbuseFilterShouldFilterAction(
		VariableHolder $vars,
		Title $title,
		User $user,
		array &$skipReasons
	) {
		if ( defined( 'MW_PHPUNIT_TEST' ) ) {
			return;
		}

		$varManager = AbuseFilterServices::getVariablesManager();

		$action = $varManager->getVar( $vars, 'action', 1 )->toString();
		if ( $action === 'autocreateaccount' ) {
			$skipReasons[] = 'Blocking automatic account creation is not allowed';

			return false;
		}
	}

	public function onCreateWikiStatePrivate( string $dbname ): void {
		/*$localRepo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
		$sitemaps = $localRepo->getBackend()->getTopFileList( [
			'dir' => $localRepo->getZonePath( 'public' ) . '/sitemaps',
			'adviseStat' => false,
		] );

		foreach ( $sitemaps as $sitemap ) {
			$status = $localRepo->getBackend()->quickDelete( [
				'src' => $localRepo->getZonePath( 'public' ) . '/sitemaps/' . $sitemap,
			] );

			if ( !$status->isOK() ) {
				$statusFormatter = MediaWikiServices::getInstance()->getFormatterFactory()
					->getStatusFormatter( RequestContext::getMain() );

				$statusMessage = $statusFormatter->getWikiText( $status );
				wfDebugLog( 'WikiOasisMagic', "Sitemap \"{$sitemap}\" failed to delete: {$statusMessage}" );
			}
		}

		$localRepo->getBackend()->clean( [ 'dir' => $localRepo->getZonePath( 'public' ) . '/sitemaps' ] );*/
	}

	public function onCreateWikiTables( array &$cTables ): void {
		$cTables['localnames'] = 'ln_wiki';
		$cTables['localuser'] = 'lu_wiki';
	}

    public function onImportDumpJobGetFile( &$filePath, $importDumpRequestManager ): void {
        wfDebugLog( 'WikiOasisMagic', "Importing dump from {$filePath}" );
        $originalFilePath = $importDumpRequestManager->getSplitFilePath();

        if ( $originalFilePath === null ) {
            return;
        }

        wfDebugLog( 'WikiOasisMagic', "Importing dump from {$originalFilePath} to {$filePath}" );

        // copy $originalFilePath to $filePath file
        if (!copy('/var/www/mediawiki/images/metawiki/'.$originalFilePath, $filePath)) {
            throw new RuntimeException("Failed to copy $originalFilePath to $filePath");
        }

        wfDebugLog( 'WikiOasisMagic', "Importing dump from {$originalFilePath} to {$filePath} done" );
	}

	/**
	 * From WikimediaMessages
	 * When core requests certain messages, change the key to a Miraheze version.
	 *
	 * @see https://www.mediawiki.org/wiki/Manual:Hooks/MessageCacheFetchOverrides
	 * @param string[] &$keys
	 */
	public function onMessageCacheFetchOverrides( array &$keys ): void {
		static $keysToOverride = [
			/*'centralauth-groupname',
			'centralauth-login-error-locked',
			'createwiki-close-email-body',
			'createwiki-close-email-sender',
			'createwiki-close-email-subject',
			'createwiki-defaultmainpage',
			'createwiki-defaultmainpage-summary',
			'createwiki-email-body',
			'createwiki-email-subject',
			'createwiki-error-subdomaintaken',
			'createwiki-help-bio',
			'createwiki-help-category',
			'createwiki-help-reason',
			'createwiki-help-subdomain',
			'createwiki-label-reason',
			'dberr-again',
			'dberr-problems',
			'globalblocking-ipblocked-range',
			'globalblocking-ipblocked-xff',
			'globalblocking-ipblocked',*/
			'grouppage-autoconfirmed',
			'grouppage-automoderated',
			'grouppage-autoreview',
			'grouppage-blockedfromchat',
			'grouppage-bot',
			'grouppage-bureaucrat',
			'grouppage-chatmod',
			'grouppage-checkuser',
			'grouppage-commentadmin',
			'grouppage-csmoderator',
			'grouppage-editor',
			'grouppage-flow-bot',
			'grouppage-interface-admin',
			'grouppage-moderator',
			'grouppage-no-ipinfo',
			'grouppage-reviewer',
			'grouppage-suppress',
			'grouppage-sysop',
			'grouppage-upwizcampeditors',
			'grouppage-user',
			/*'importdump-help-reason',
			'importdump-help-target',
			'importdump-help-upload-file',
			'importdump-import-failed-comment',
			'importtext',
			'interwiki_intro',
			'newsignuppage-loginform-tos',
			'newsignuppage-must-accept-tos',
			'oathauth-step1',
			'prefs-help-realname',
			'privacypage',
			'requestwiki-error-invalidcomment',
			'requestwiki-info-guidance',
			'requestwiki-info-guidance-post',
			'requestwiki-label-agreement',
			'requestwiki-success',
			'restriction-delete',
			'restriction-protect',
			'skinname-snapwikiskin',
			'snapwikiskin',
			'uploadtext',
			'webauthn-module-description',
			'wikibase-sitelinks-miraheze',*/
		];

		$languageCode = $this->options->get( MainConfigNames::LanguageCode );

		$transformationCallback = static function ( string $key, MessageCache $cache ) use ( $languageCode ): string {
			$transformedKey = "wikioasis-$key";

			// MessageCache uses ucfirst if ord( key ) is < 128, which is true of all
			// of the above.  Revisit if non-ASCII keys are used.
			$ucKey = ucfirst( $key );

			if (
				/*
				 * Override order:
				 * 1. If the MediaWiki:$ucKey page exists, use the key unprefixed
				 * (in all languages) with normal fallback order.  Specific
				 * language pages (MediaWiki:$ucKey/xy) are not checked when
				 * deciding which key to use, but are still used if applicable
				 * after the key is decided.
				 *
				 * 2. Otherwise, use the prefixed key with normal fallback order
				 * (including MediaWiki pages if they exist).
				 */
				$cache->getMsgFromNamespace( $ucKey, $languageCode ) === false
			) {
				return $transformedKey;
			}

			return $key;
		};

		foreach ( $keysToOverride as $key ) {
			$keys[$key] = $transformationCallback;
		}
	}

	public function onTitleReadWhitelist( $title, $user, &$whitelisted ) {
		if ( $title->equals( Title::newMainPage() ) ) {
			$whitelisted = true;
			return;
		}

		$specialsArray = [
			'CentralAutoLogin',
			'CentralLogin',
			'ConfirmEmail',
			'CreateAccount',
			'Notifications',
			'OAuth',
			'ResetPassword'
		];

		if ( $user->isAllowed( 'interwiki' ) ) {
			$specialsArray[] = 'Interwiki';
		}

		if ( $title->isSpecialPage() ) {
			$rootName = strtok( $title->getText(), '/' );
			$rootTitle = Title::makeTitle( $title->getNamespace(), $rootName );

			foreach ( $specialsArray as $page ) {
				if ( $rootTitle->equals( SpecialPage::getTitleFor( $page ) ) ) {
					$whitelisted = true;
					return;
				}
			}
		}
	}

	public function onGlobalUserPageWikis( array &$list ): bool {
		$cwCacheDir = $this->options->get( 'CreateWikiCacheDirectory' );

		if ( file_exists( "{$cwCacheDir}/databases.php" ) ) {
			$databasesArray = include "{$cwCacheDir}/databases.php";

			$dbList = array_keys( $databasesArray['databases'] ?? [] );

			// Filter out those databases that don't have GlobalUserPage enabled
			$list = array_filter( $dbList, static function ( $dbname ) {
				$extensions = new ManageWikiExtensions( $dbname );
				return in_array( 'globaluserpage', $extensions->list() );
			} );

			return false;
		}

		return true;
	}

	public function onMimeMagicInit( $mimeMagic ) {
		$mimeMagic->addExtraTypes( 'text/plain txt off' );
	}

	public function onSkinAddFooterLinks( Skin $skin, string $key, array &$footerItems ) {
		/*if ( $key === 'places' ) {
			$footerItems['termsofservice'] = $this->addFooterLink( $skin, 'termsofservice', 'termsofservicepage' );
			$footerItems['donate'] = $this->addFooterLink( $skin, 'miraheze-donate', 'miraheze-donatepage' );
		}*/
	}

	public function onSiteNoticeAfter( &$siteNotice, $skin ) {
		/*$cwConfig = new GlobalVarConfig( 'cw' );

		if ( $cwConfig->get( 'Closed' ) ) {
			if ( $cwConfig->get( 'Private' ) ) {
				$siteNotice .= '<div class="wikitable" style="text-align: center; width: 90%; margin-left: auto; margin-right:auto; padding: 15px; border: 4px solid black; background-color: #EEE;"> <span class="plainlinks"> <img src="https://static.miraheze.org/metawiki/0/02/Wiki_lock.png" align="left" style="width:80px;height:90px;">' . $skin->msg( 'miraheze-sitenotice-closed-private' )->parse() . '</span></div>';
			} elseif ( $cwConfig->get( 'Locked' ) ) {
				$siteNotice .= '<div class="wikitable" style="text-align: center; width: 90%; margin-left: auto; margin-right:auto; padding: 15px; border: 4px solid black; background-color: #EEE;"> <span class="plainlinks"> <img src="https://static.miraheze.org/metawiki/5/5f/Out_of_date_clock_icon.png" align="left" style="width:80px;height:90px;">' . $skin->msg( 'miraheze-sitenotice-closed-locked' )->parse() . '</span></div>';
			} else {
				$siteNotice .= '<div class="wikitable" style="text-align: center; width: 90%; margin-left: auto; margin-right:auto; padding: 15px; border: 4px solid black; background-color: #EEE;"> <span class="plainlinks"> <img src="https://static.miraheze.org/metawiki/0/02/Wiki_lock.png" align="left" style="width:80px;height:90px;">' . $skin->msg( 'miraheze-sitenotice-closed' )->parse() . '</span></div>';
			}
		} elseif ( $cwConfig->get( 'Inactive' ) && $cwConfig->get( 'Inactive' ) !== 'exempt' ) {
			if ( $cwConfig->get( 'Private' ) ) {
				$siteNotice .= '<div class="wikitable" style="text-align: center; width: 90%; margin-left: auto; margin-right:auto; padding: 15px; border: 4px solid black; background-color: #EEE;"> <span class="plainlinks"> <img src="https://static.miraheze.org/metawiki/5/5f/Out_of_date_clock_icon.png" align="left" style="width:80px;height:90px;">' . $skin->msg( 'miraheze-sitenotice-inactive-private' )->parse() . '</span></div>';
			} else {
				$siteNotice .= '<div class="wikitable" style="text-align: center; width: 90%; margin-left: auto; margin-right:auto; padding: 15px; border: 4px solid black; background-color: #EEE;"> <span class="plainlinks"> <img src="https://static.miraheze.org/metawiki/5/5f/Out_of_date_clock_icon.png" align="left" style="width:80px;height:90px;">' . $skin->msg( 'miraheze-sitenotice-inactive' )->parse() . '</span></div>';
			}
		}*/
	}

	public function onContributionsToolLinks( $id, Title $title, array &$tools, SpecialPage $specialPage ) {
		$username = $title->getText();

		if ( !IPUtils::isIPAddress( $username ) ) {
			$globalUserGroups = CentralAuthUser::getInstanceByName( $username )->getGlobalGroups();

			if (
				!in_array( 'steward', $globalUserGroups ) &&
				!in_array( 'global-sysop', $globalUserGroups ) &&
				!$specialPage->getUser()->isAllowed( 'centralauth-lock' )
			) {
				return;
			}

			$tools['centralauth'] = Linker::makeExternalLink(
				'https://meta.wikioasis.org/wiki/Special:CentralAuth/' . $username,
				strtolower( $specialPage->msg( 'centralauth' )->text() )
			);
		}
	}

	/**
	 * phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
	 *
	 * @param Title $title
	 * @param string &$url
	 * @param string $query
	 */
	public function onGetLocalURL__Internal( $title, &$url, $query ) {
		// phpcs:enable

		if ( defined( 'MW_PHPUNIT_TEST' ) ) {
			return;
		}

		// If the URL contains wgScript, rewrite it to use wgArticlePath
		if ( str_contains( $url, $this->options->get( MainConfigNames::Script ) ) ) {
			$dbkey = wfUrlencode( $title->getPrefixedDBkey() );
			$url = str_replace( '$1', $dbkey, $this->options->get( MainConfigNames::ArticlePath ) );
			if ( $query !== '' ) {
				$url = wfAppendQuery( $url, $query );
			}
		}
	}

	private function addFooterLink( $skin, $desc, $page ) {
		if ( $skin->msg( $desc )->inContentLanguage()->isDisabled() ) {
			$title = null;
		} else {
			$title = Title::newFromText( $skin->msg( $page )->inContentLanguage()->text() );
		}

		if ( !$title ) {
			return '';
		}

		return Html::element( 'a',
			[ 'href' => $title->fixSpecialName()->getLinkURL() ],
			$skin->msg( $desc )->text()
		);
	}

	/** Removes redis keys for jobrunner */
	private function removeRedisKey( string $key ) {
		$jobTypeConf = $this->options->get( MainConfigNames::JobTypeConf );
		if ( !isset( $jobTypeConf['default']['redisServer'] ) || !$jobTypeConf['default']['redisServer'] ) {
			return;
		}

		$hostAndPort = IPUtils::splitHostAndPort( $jobTypeConf['default']['redisServer'] );

		if ( $hostAndPort ) {
			try {
				$redis = new Redis();
				$redis->connect( $hostAndPort[0], $hostAndPort[1] );
				$redis->auth( $jobTypeConf['default']['redisConfig']['password'] );
				$redis->del( $redis->keys( $key ) );
			} catch ( Throwable $ex ) {
				// empty
			}
		}
	}

	/** Remove memcached keys */
	private function removeMemcachedKey( string $key ) {
		$memcachedServers = $this->options->get( 'WikiOasisMemcachedServers' );

		try {
			foreach ( $memcachedServers as $memcachedServer ) {
				$memcached = new Memcached();

				$memcached->addServer( $memcachedServer[0], (string)$memcachedServer[1] );

				// Fetch all keys
				$keys = $memcached->getAllKeys();
				if ( !is_array( $keys ) ) {
					return;
				}

				foreach ( $keys as $item ) {
					// Decide which keys to delete
					if ( preg_match( "/{$key}/", $item ) ) {
						$memcached->delete( $item );
					} else {
						continue;
					}
				}
			}
		} catch ( Throwable $ex ) {
			// empty
		}
	}
}
SkywikiMagic/includes/SpecialChangeDomain.php0000644000000000000000000001212114727411650020310 0ustar  rootroot<?php

namespace WikiOasis\WikiOasisMagic;

use ErrorPageError;
use MediaWiki\Html\Html;
use MediaWiki\Message\Message;
use MediaWiki\HTMLForm\HTMLForm;
use MediaWiki\SpecialPage\SpecialPage;
use Miraheze\CreateWiki\ConfigNames;
use Miraheze\CreateWiki\Services\CreateWikiDatabaseUtils;
use Miraheze\CreateWiki\Services\RemoteWikiFactory;
use ManualLogEntry;

class SpecialChangeDomain extends SpecialPage {

	private CreateWikiDatabaseUtils $databaseUtils;
	private RemoteWikiFactory $remoteWikiFactory;

	public function __construct(
		CreateWikiDatabaseUtils $databaseUtils,
		RemoteWikiFactory $remoteWikiFactory
	) {
		parent::__construct( 'ChangeDomain', 'managewiki-restricted' );

		$this->databaseUtils = $databaseUtils;
		$this->remoteWikiFactory = $remoteWikiFactory;
	}

	/**
	 * @param ?string $par
	 */
	public function execute( $par ): void {
		if ( !$this->databaseUtils->isCurrentWikiCentral() ) {
			throw new ErrorPageError( 'errorpagetitle', 'createwiki-wikinotcentralwiki' );
		}
		$par = explode( '/', $par ?? '', 3 );

		$this->getOutput()->setPageTitle( 'Change domain' );
		if ( $par[0] == '' ) {
			$this->showInputBox();
		} else {
			$this->showWikiForm( $par[0] );
		}
	}


	public function showInputBox() {
		$formDescriptor = [
			'info' => [
				'default' => $this->msg( 'changedomain-info' )->text(),
				'type' => 'info',
			],
			'dbname' => [
				'label-message' => 'managewiki-label-dbname',
				'type' => 'text',
				'size' => 20,
				'required' => true
			]
		];

		if ( !$this->getContext()->getUser()->isAllowed( 'managewiki-restricted' ) ) {
                        $this->getOutput()->addHTML(
                                Html::errorBox( $this->msg( 'managewiki-error-nopermission' )->escaped() )
                        );
		}

		$htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext(), 'searchForm' );
		$htmlForm->setWrapperLegendMsg( 'managewiki-core-header' );
		$htmlForm->setMethod( 'post' )
			->setSubmitCallback( [ $this, 'onSubmitRedirectToWikiForm' ] )
			->prepareForm()
			->show();

		return true;
	}


	public function onSubmitRedirectToWikiForm( array $params ) {
		if ( $params['dbname'] !== '' ) {
			header( 'Location: ' . SpecialPage::getTitleFor( 'ChangeDomain' )->getFullURL() . '/' . $params['dbname'] );
		} else {
			return 'Invalid url.';
		}

		return true;
	}


	public function showWikiForm( $wiki ) {
		$out = $this->getOutput();

		$out->addModules( [ 'ext.managewiki.oouiform' ] );

		$out->addModuleStyles( [
			'ext.managewiki.oouiform.styles',
			'mediawiki.widgets.TagMultiselectWidget.styles',
		] );

		$out->addModuleStyles( [ 'oojs-ui-widgets.styles' ] );
		$out->addModules( [ 'mediawiki.special.userrights' ] );

		$remoteWiki = $this->remoteWikiFactory->newInstance( $wiki );

		if ( $remoteWiki->isLocked() ) {
			$out->addHTML( Html::errorBox( $this->msg( 'managewiki-mwlocked' )->escaped() ) );
		}

		$options = [];

                $formDescriptor = [
			'wiki' => [
			        'type' => 'hidden',
			        'name' => 'wiki',
			        'default' => $wiki,
    			],
                        'subdomain' => [
                                'default' => $remoteWiki->getServerName(),
                                'label-message' => 'changedomain-label-domain',
                                'type' => 'text',
                                'size' => 20
			]
		];

		$htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext(), 'changesubdomain' );

		$htmlForm->setSubmitTextMsg( 'managewiki-save' );

                $htmlForm->setSubmitCallback( [ $this, 'submitForm' ] );

		if ( !$this->getContext()->getUser()->isAllowed( 'managewiki-restricted' ) ) {
			$out->addHTML(
				Html::errorBox( $this->msg( 'managewiki-error-nopermission' )->escaped() )
			);
		}

		$htmlForm->show();
	}

        public function submitForm( array $params ) {
                $out = $this->getOutput();

                $remoteWiki = $this->remoteWikiFactory->newInstance( $params['wiki'] );

                if ( $remoteWiki->isLocked() ) {
			$out->addHTML( Html::errorBox( $this->msg( 'managewiki-mwlocked' )->escaped() ) );
			return;
		}

		if ( !$this->getContext()->getUser()->isAllowed( 'managewiki-restricted' ) ) {
			$out->addHTML(
				Html::errorBox( $this->msg( 'managewiki-error-nopermission' )->escaped() )
			);
			return;
		}

		$remoteWiki->setServerName( $params['subdomain'] );
		$remoteWiki->commit();
                $logEntry = new ManualLogEntry( 'managewiki', 'settings' );
                $logEntry->setPerformer( $this->getUser() );
                $logEntry->setTarget( SpecialPage::getTitleValueFor( 'ChangeDomain', (string)$params['wiki'] ) );
                $logEntry->setParameters( [ '4::wiki' => $params['wiki'], '5::changes' => 'servername' ] );
                $logID = $logEntry->insert();
                $logEntry->publish( $logID );
		$out->addHTML(
			Html::successBox(
				Html::element(
					'p',
					[],
					wfMessage( 'managewiki-success' )->plain()
				),
				'mw-notify-success'
			)
		);

                return true;
        }

	/**
	 * @inheritDoc
	 */
	protected function getGroupName(): string {
		return 'wikimanage';
	}
}