User:AntiCompositeNumber/PermissionOTRS.js

/** PermissionOTRS.js /* eslint indent:["error","tab",{"outerIIFEBody":0}] */ /* eslint no-underscore-dangle:0 */ /* global mediaWiki, jQuery, OO */ /* jshint curly:false, scripturl:true, forin:false */ ( function ( $, mw ) { 'use strict';
 * @description: Adds OTRS permission template via API. Other templates such as {OTRS pending} will be removed.
 * @revision: 23:07, 16 August 2018 (UTC)
 * @source: https://commons.wikimedia.org/wiki/MediaWiki:Gadget-PermissionOTRS.js
 * @license: under the terms of the MIT license
 * @authors:
 * Maintainer: User:Perhelion
 * Created by Bryan Tong Minh
 * Amended by de:User:DerHexer, User:Guandalug, DieBuche, User:Steinsplitter, User:Rillke
 * Rewritten by Perhelion, Fordította: :hu:User:Bencemac
 * @required modules: mediawiki.util, oojs-ui-core, oojs-ui-windows, mediawiki.api

var c = mw.config.get( [		'wgCategories',		'wgIsArticle',		'wgGlobalGroups',		'wgNamespaceNumber',		'wgPageName',		// 'wgRestrictionEdit',		'wgUserGroups',		'wgUserLanguage',		'wgUserName'	] ), user = c.wgUserName, page = c.wgPageName, sLink = 'OTRS ', oChangeTag = 'PermissionOTRS', ticket, content, // timestamp, reason = '', deferred = null, editform = null, received = false, i18n = { de: { apiErrorCode: 'Fehler bei der Verarbeitung der Anfrage.\n\t API-Fehlercode: %CODE%\n\n\tBitte versuche es erneut.', confirmDR: 'Melde dies beim Löschantrag?', digit: 'Ticket-ID (16-stellige Nummer):', Done: 'Fertig!', emptyResponse: 'Eine leere Antwort vom Server erhalten.', // Error: 'Fehler!', fail: 'fehlgeschlagen', gotContent: 'Inhalt der Seite erhalten…', // INVALIDID: 'INVALIDE ID', invalidId: 'Es muss eine gültige 16-stellige Ticket-Nummer eingeben werden.', noAuth: 'Du bist für diese Funktion nicht berechtigt!', noFound: 'Keine passende Stelle zum Einfügen der Vorlage gefunden! Bitte von Hand hinzufügen.', process: '…Anfrage zur Kennzeichnung mit Ticket#: %TICKET%', Processing: 'Verarbeitung …', reason: 'Gib eine Begründung?', sameTicket: 'Gleiches Ticket bereits hinzugefügt.', success: 'OTRS-Ticket erfolgreich eingefügt.' },		hu: { apiErrorCode: 'Hiba lépett fel a művelet végrehajtása során.\n\t API-hibakód:%CODE%\n\n\tKérlek, próbáld újra!', digit: 'Ticket ID (16 jegyű szám):', Done: 'Kész!', emptyResponse: 'Üres válasz érkezett a szervertől.', Error: 'Hiba!', fail: 'hiba', gotContent: 'Az oldal tartalmának betöltése…', invalidId: 'Adj meg egy érvényes 16 számjegyű számot.', noAuth: 'Nincs jogosultságod a művelet végrehajtásához!', noFound: 'Nem található megfelelő hely a sablon beillesztésére. Írd be kézzel.', process: 'Az összekapcsolás a(z) %TICKET% számú jeggyel elkezdődött', Processing: 'Folyamatban…', sameTicket: 'A jegy már szerepel az oldalon.', success: 'OTRS jegy sikeresen hozzáadva.' },		apiErrorCode: 'There was an error processing your request.\n\t API-error-code: %CODE%\n\n\tPlease try again.', confirmDR: 'Report this to the deletion request?', digit: 'Ticket ID (16 digit number):', Done: 'Done!', emptyResponse: 'Got an empty response from the server.', Error: 'Error!', fail: 'fail', gotContent: 'Got page contents…', INVALIDID: 'INVALID ID', invalidId: 'You must enter a valid 16-digit ticket number.', noAuth: 'You are not authorized for this function!', noFound: 'No suitable place found to insert the template! Please add by hand.', process: '…request to tag with Ticket#: %TICKET%', Processing: 'Processing…', reason: 'Give a reason?', sameTicket: 'Same ticket already added.', success: 'OTRS ticket successfully inserted.' };

if ( c.wgNamespaceNumber !== 6 || $.inArray( 'autoconfirmed', c.wgUserGroups ) === -1 || !user ) { return; } if ( !c.wgIsArticle ) { editform = $( '#wpTextbox1' ); }

function _apiFail( code, r ) { if ( code === 'http' ) { r = 'HTTP error: ' + r.textStatus; } else if ( code === 'ok-but-empty' ) { r = i18n.emptyResponse; } else { r = 'API ' + i18n.fail + ': ' + code; }	mw.log.warn( r ); mw.notify( i18n.apiErrorCode.replace( '%CODE%', code ), {		title: i18n.Error,		autoHide: 0,		type: 'error'	} ); }

function doDoneMsg { mw.notify( i18n.success, {		title: i18n.Done	} ).done( function {		// true if not edit-mode		if ( deferred ) { location.reload; }	} ); }

/*function addHintOnDR( lastMatch ) { mw.loader.using( 'user.options', function {		var uSig = ( mw.user.options.get( 'fancysig' ) && mw.user.options.get( 'nickname' ).search( /^[ ']*\[\[/ ) ) ?				' ' : ' --',			DR = /subpage ?= ?([^|]+)\|/.exec( lastMatch );		DR = ( DR && ( DR = DR[ 1 ] ) ) || page;		new mw.Api.edit( 'Commons:Deletion_requests/' + DR.replace( ' ', '_' ), function ( revision ) { var text = revision.content; // if really open if ( text && !/\{\{[Dd]elf\}\}\s*$/.test( text ) ) { text += '\n* OTRS modern logo.svg ' + ( received ?						'There is an OTRS email received for “' + page + '” but not processed yet, ' + ticket + '.' :						'I have just accepted permission for “' + page + '” under ' + ticket + '.' ); // and tagged it as such return { text: text + uSig + '~\n', // nowiki summary: 'OTRS ticket received', watchlist: 'preferences', assert: 'user', notminor: 1 };				} else { mw.notify( 'Deletion request already closed.', {						title: 'Notification failed ',						type: 'warn'					} ); return $.Deferred.fail; }			} )			.done( function { mw.notify( 'Notification successfully added.', {					title: 'Notify on deletion request'				} ).done( function {					doDoneMsg;				} ); } ).fail( _apiFail );	} ); }*/

/*function doneMsg { // Add message on possible DR	if ( /\{\{[Dd]elete[^}\n]*\}\}/.test( content ) ) { var match = RegExp.lastMatch; OO.ui.confirm( i18n.confirmDR ).done( function ( confirmed ) {			if ( confirmed ) {				addHintOnDR( match );			} else { doDoneMsg; }		} ); } else { doDoneMsg; } }*/

function _getPage( OTRS ) { if ( !editform ) { mw.notify( OTRS.name + ': ' + i18n.process.replace( /%TICKET%/, ticket ), {			title: i18n.Processing		} );

new mw.Api.edit(			page,			function ( revision ) {				mw.notify( i18n.gotContent, { title: i18n.Processing } );				content = revision.content;				// timestamp = revision.timestamp;				deferred = $.Deferred;				OTRS;				return deferred.promise;			} ).done( doneMsg ).fail( _apiFail ); } else { content = editform.val; return OTRS; } }

function _prompt( text, OTRS ) { var OTRSfield = $( '#field-otrs' ), // there is already a ticket name = 'OTRS', $select, type = 'errorbox', noprompt = false, // whether we expect input title = ( OTRS && OTRS.name ) ? OTRS.name : name;

// try pre-fill the ticket if ( OTRSfield.length ) { ticket = OTRSfield.attr( 'title' ).replace( /[^\n]+(\d{16})$/, '$1' ); } else if ( editform && /\{\{otrs[ _]received\|id=(\d{16})+[^}\n]*\}\}/i.test( editform.val ) ) { ticket = RegExp.$1; }	if ( !text ) { if ( received ) { $select = 1; }		title = i18n.INVALIDID; text = i18n.invalidId;

} else if ( text === 'FAIL' ) { title = text; text = i18n.noFound; noprompt = 1; } else { type = ''; }

if ( type ) { text = $( ' ' ) .addClass( type ) .text( text ); } else if ( received ) { // Reason checkbox $select = 1; }

mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-windows' ], function {		/* Code taken from oojs-ui-windows #OO-ui-method-prompt */		function OOuiPrompt( text, options ) {			var instance,				manager = OO.ui.getWindowManager,				textInput = new OO.ui.TextInputWidget( ( options && options.textInput ) || {} ),				textField = new OO.ui.FieldLayout( textInput, { align: 'top', label: text } ),				dropDown,				checkbox = options.textInput.checkbox,				fieldset = [ textField ];

if ( checkbox ) { dropDown = new OO.ui.DropdownInputWidget( {					id: name + 'combo',					// label: '',					disabled: true,					options: [						{ data: 'a', label: 'processing' },						{ data: 'b', label: 'licence' },						{ data: 'c', label: 'email' }					]				} ); checkbox = new OO.ui.CheckboxInputWidget( {					id: name + 'reason'				} ).on( 'change', function {					reason = dropDown.isDisabled;					dropDown.setDisabled( !reason );					// $select.toggle;				} );

checkbox = new OO.ui.FieldLayout( checkbox, { label: i18n.reason, align: 'inline' } ); $select = dropDown.$element; fieldset.push( checkbox ); fieldset.push( dropDown ); }

fieldset = new OO.ui.FieldsetLayout( {/* label: 'Checkbox'*/} ) .addItems( fieldset );

instance = manager.openWindow( 'message', $.extend( { title: textInput.title, message: fieldset.$element }, options ) );

instance.opened.then( function {				textInput.on( 'enter', function  { manager.getCurrentWindow.close( { action: 'accept' } ); } );				textInput.focus;			} );

return instance.closed.then( function ( data ) {				return data && data.action === 'accept' ? textInput.getValue : null;			} ); }

if ( noprompt ) { OO.ui.alert( text ); } else { new OOuiPrompt( text, {				textInput: {					title: title,					maxLength: 23, // For possible pre-phrase "Ticket#"					validate: /^\s*(Ticket)?#?\d{16}\s*$/,					checkbox: !!$select,					value: ticket				}			} ).done( function ( result ) {				ticket = $.trim( result ).replace( /^(Ticket)?#?/,  ); // clean up input				reason = ( reason && typeof $select === 'object' ) ? $select.find( 'option:selected' ).text : ;				if ( ticket ) { // Check ticket validity					if ( /^\d{16}$/.test( ticket ) ) {						_getPage( OTRS );					} else { // Try again						_prompt( '', OTRS );					}				}			} ); }	} ); }

function _savePage( summary ) { if ( deferred ) { deferred.resolve( {			text: content,			summary: summary,			watchlist: 'preferences',			tags: oChangeTag,			notminor: 1		} ); } else { // In edit-mode $( '#wpMinoredit' ).prop( 'checked', 0 ); editform.val( content ); $( '#wpSummary' ).val( function ( i, v ) {			return $.trim( v.replace( summary, '' ) + ' ' + summary );		} ); doneMsg; } }

function _cleanUp( text ) { // ToDo: maybe here could be loaded another general cleanup module!? return $.trim( text //		.replace( /== ?Summary ?==/, '====' ) //		.replace( /== ?Licensing ?==/, '====' )		.replace( /\{\{OTRS[ _-](pending|received)[^}\n]*\}\}\s?/ig,  )		.replace( /\{\{[Nn]o[ _](OTRS[ _])?permission[^}\n]*\}\}\s*/g, '\n' )		.replace( /<(!--|nowiki>)\s*\{\{([Pp]ermission[ _]?)?OTRS ?\| ?id= ?\d+\s*[^}\n]*\}\}\s*(--|<\/nowiki)>\s?/g,  )		// Remove problem since tags (X-To-DR string)		.replace( /\{\{\s*[Nn]o[ _](source|permission|license)([ _]since)?\s*(\|[^}\n]+)?\}\}\s?/g,  )		// Remove Copyvio (X-To-DR string)		.replace( /\{\{\s*(Copyviol?|Copyright(?:ed)?|Screenshot|Icon|Logo|Logo-Germany|(?:Non-free video |DVD )?Cover|Db-f9|db-copyvio|Vio(?:lation)?)\s*(\|[^\n]+|[^}\n]*)\}\}\s?/i,  )		// Remove Speedy (X-To-DR string)		.replace( /\{\{\s*(Speedy(?:[ -]?delet(?:e|ion))?|Speedilydelete|Noncommercial|Nonderivative|löschen|db|spd|qd|Sdelete|SLA|Spdel|Ek|Destruir)\s*(\|[^\n]+|[^}\n]*)\}\}\s?/i, '' ) .replace( /\{\{\s*SD\s*(\|[^\n]+|[^}\n]*)\}\}\s?/, '' ) ); // Remove SD (not Sd) }

function _addPermission( template, summary ) { var text = _cleanUp( content ), textBefore = text, regP = /*\|\s*[Pp]ermission*=\s*([^\n]*\n)/, regA = /*\|\s*[Aa]uthor*=\s*[^\n]*\n/g; // fallback position, if no permission parameter if ( !regP.test( text ) ) { if ( !regA.test( text ) ) { return _prompt( 'FAIL' ); }		var l = regA.lastIndex, s1 = RegExp.$1 || '', // leading whitespaces as indent? s2 = ( RegExp.$2 ) ? ' ' : '', // whitespace on parameter? sr = text.substr( l ).search( /^\s*(\||\}\})/m ); // try to got at template end if ( sr >= 0 ) { sr += l; // insert to the end of information template text = text.substr( 0, sr ) + s1 + '|permission' + s2 + '=' + s2 + template + '\n' + text.substr( sr ); } else { return _prompt( 'FAIL' ); }	} else { if ( text.indexOf( template ) > 0 ) { return mw.notify( i18n.sameTicket, {				title: 'OTRS ' + i18n.fail + '…',				type: 'warn'			} ); }		text = text.replace( regP, '$1|permission$2=$2' + template + '\n$3' ); }	if ( textBefore === text ) { return _prompt( 'FAIL' ); }	content = text; _savePage( sLink + summary ); }

var PermissionOTRS = function PermissionOTRS { _addPermission( '',			'permission added' ); },

OTRSreceived = function OTRSreceived { _addPermission(			'',			'email received but not processed yet' ); };

function dialogOTRS( e, OTRS ) { e.preventDefault; // Merge languages // TODO: could be improved with mw.language.getFallbackLanguages $.extend( true, i18n, i18n[ c.wgUserLanguage ] );

function chkuGrp( b ) { if ( b ) { _prompt( i18n.digit, OTRS ); } else { mw.notify( i18n.noAuth, {				title: 'OTRS ' + i18n.fail + '!',				type: 'warn'			} ); }	}	mw.loader.using( [ 'mediawiki.api' ], function {		if ( $.inArray( 'otrs-member', c.wgGlobalGroups ) > -1 || $.inArray( 'sysop', c.wgUserGroups ) > -1 ) {			chkuGrp( 1 );		} else { // Fallback?			new mw.Api.get( { meta: 'globaluserinfo', guiuser: user, guiprop: 'groups' } ).done( function ( r ) { chkuGrp( ( $.inArray( 'otrs-member', r.query.globaluserinfo.groups ) > -1 ) ); } ).fail( function ( code, r ) { _apiFail( code, r ); } );		}	} ); }

mw.loader.using( 'mediawiki.util', function {	var bReceive,		bConfirm; // booleans; add link only if needed

$.each( c.wgCategories, function ( i, text ) {		if ( text && !( bReceive && bConfirm ) ) { // Check Cats			if ( /^Items with (ticket )?OTRS permission confirmed/.test( text ) ) {				bConfirm = bReceive = true;			} else if ( /^OTRS received/.test( text ) ) {				bReceive = true;			}		}	} );

if ( !bConfirm ) { bConfirm = [ $( mw.util.addPortletLink( 'p-tb', '#', 'Permission OTRS' ) ) .on( 'click', function ( e ) {				received = 0;				dialogOTRS( e, PermissionOTRS );			} ) ]; if ( !bReceive ) { bConfirm[ 1 ] = $( mw.util.addPortletLink( 'p-tb', '#', 'OTRS received' ) ) .on( 'click', function ( e ) {					received = 1;					dialogOTRS( e, OTRSreceived );				} ); }		$.each( bConfirm, function ( i, link ) {			link.find( 'a' ).css( 'color', '#D82' );		} ); } } ); }( jQuery, mediaWiki ) ); // EOF