Index: trunk/extensions/UploadWizard/UploadWizardHooks.php |
— | — | @@ -42,6 +42,9 @@ |
43 | 43 | // mediawiki-specific interface helper (relies on mediawiki globals) |
44 | 44 | 'resources/jquery/jquery.mwCoolCats.js', |
45 | 45 | |
| 46 | + // wikimedia-comons specific title checker |
| 47 | + 'resources/jquery/jquery.validate.wmCommonsBlacklist.js', |
| 48 | + |
46 | 49 | // common utilities |
47 | 50 | 'resources/mw.Log.js', |
48 | 51 | 'resources/mw.Utilities.js', |
— | — | @@ -254,6 +257,11 @@ |
255 | 258 | 'mwe-upwiz-error-too-short', |
256 | 259 | 'mwe-upwiz-error-bad-chars', |
257 | 260 | 'mwe-upwiz-error-date', |
| 261 | + 'mwe-upwiz-error-title-blacklisted', |
| 262 | + 'mwe-upwiz-error-title-badchars', |
| 263 | + 'mwe-upwiz-error-title-senselessimagename', |
| 264 | + 'mwe-upwiz-error-title-hosting', |
| 265 | + 'mwe-upwiz-error-title-thumbnail', |
258 | 266 | 'mwe-upwiz-license-cc-by-sa-3.0', |
259 | 267 | 'mwe-upwiz-license-cc-by-3.0', |
260 | 268 | 'mwe-upwiz-license-cc-zero', |
Index: trunk/extensions/UploadWizard/UploadWizard.i18n.php |
— | — | @@ -177,6 +177,11 @@ |
178 | 178 | 'mwe-upwiz-error-bad-chars' => 'This field contains symbols that are not allowed. |
179 | 179 | Please do not use wikitext or HTML here.', |
180 | 180 | 'mwe-upwiz-error-date' => 'Please enter a valid date in YYYY-MM-DD format, or pick a date from the popup calendar.', |
| 181 | + 'mwe-upwiz-error-title-blacklisted' => 'This title contains some undesirable text. Please revise it', |
| 182 | + 'mwe-upwiz-error-title-badchars' => 'This title contains some undesirable characters. Please remove them', |
| 183 | + 'mwe-upwiz-error-title-senselessimagename' => 'Please make this title more meaningful.', |
| 184 | + 'mwe-upwiz-error-title-hosting' => 'This looks like a file you obtained from another imagehost. Please make the title more meaningful. Also, double check that you have the rights to publish it on {{SITENAME}}.', |
| 185 | + 'mwe-upwiz-error-title-thumbnail' => 'This looks like a thumbnail title. Please do not upload thumbnails back to the same wiki. Otherwise, please fix the filename so it is more meaningful, and does not have the thumbnail prefix.', |
181 | 186 | |
182 | 187 | /* LICENSES & combinations of licenses */ |
183 | 188 | /* may be a good idea to shift to WikimediaLicenseTexts? */ |
Index: trunk/extensions/UploadWizard/resources/jquery/jquery.validate.wmCommonsBlacklist.js |
— | — | @@ -0,0 +1,117 @@ |
| 2 | +/** |
| 3 | + * One day this will look up an API method to determine if a filename is blacklisted by your local MediaWiki |
| 4 | + * For now we check with some regexes locally, with a Commons-specific blacklist |
| 5 | + * This is an incomplete rendering of the meta.wikimedia.org and commons.wikimedia.org blacklist as they existed on 2011-05-05, and |
| 6 | + * ignores cases that are irrelevant to uploading new media images. |
| 7 | + * - all regexes are case INsensitive by default |
| 8 | + * - casesensitive is considered |
| 9 | + * - errmsg is considered |
| 10 | + * - namespaces and File: prefix are removed since everything we upload is under File: anyway |
| 11 | + * - noedit, moveonly, repuload is irrelevant |
| 12 | + * - we can't check autoconfirmed-ness of users here, so we ignore it |
| 13 | + * - Javascript doesn't have a standard way to access unicode character properties in regexes, so \p{PROPERTY}, \P{PROPERTY}, and [[:PROPERTY:]] have been changed when possible |
| 14 | + * or the associated regex removed |
| 15 | +*/ |
| 16 | +( function( $ ) { |
| 17 | + |
| 18 | + var regexSets = { |
| 19 | + |
| 20 | + 'titleBlacklist': [ |
| 21 | + /(?:suck|his|your|my) penis/i, |
| 22 | + /\bnimp\.org./i, |
| 23 | + /Lawl,/i, |
| 24 | + /HAGG[EA]R[^A-Z]*/i, |
| 25 | + /[НHΗ][EЕΕ]R[MМΜ][YΥ]/, |
| 26 | + /[НHΗ][AΑΑ]GG[EЕΕ]R/, |
| 27 | + /[НH]\W*[AΑΑ]\W*G\W*G\W*[EЕΕ]\W*R(?!ston)/i, |
| 28 | + /\bHERMY/, |
| 29 | + / on wheels/i, |
| 30 | + /(?:.*?\/)?index\.php(?:\/.*)?/i, |
| 31 | + /(?:http|https|ftp|mailto|torrent|ed2k)\:\/\/[\w\d:@\-]+\.[\w\d\-]+/i, |
| 32 | + /http:\/\//i, |
| 33 | + /\/wiki\//i, |
| 34 | + /\bis\s+(?:a|an)\s+(?:dick|cunt|fag|bitch|shit|fuck|fucker|loser|ass|gay|ghey|moron|retard|stupid|slut|pa?edo)/i, |
| 35 | + /\sprefix:/i, // search from inputboxes (f.e. in the village pumps) |
| 36 | + /.*[!?]{3,}.* /i, |
| 37 | + /(?:[^\/i]+[\/:])?(index\.php|w\/wiki)(?:\/.+)?/, |
| 38 | + /[НHΗHⱧ][EЕΕËEĖ][RRЯ][MМΜM][YΥY]/i, |
| 39 | + /JEWS DID/i, |
| 40 | + /ON WHE/, |
| 41 | + /(?:Moulton|Barsoom Tork|Pocoyo Albatross|Anything Muppets|Moosey Mouse|Inbloomed Muppets).*/, |
| 42 | + /Jorge Queirolo Bravo/i, |
| 43 | + /Vasilisa(\d)+/i, |
| 44 | + /google.*\.html/i |
| 45 | + ], |
| 46 | + |
| 47 | + 'titleBadchars': [ |
| 48 | + /[\u00A0\u1680\u180E\u2000-\u200B\u2028\u2029\u202F\u205F\u3000]/, // NBSP and other unusual spaces |
| 49 | + /[\u202A-\u202E]/, // BiDi overrides |
| 50 | + /[\x00-\x1f]/, // Control characters |
| 51 | + /\uFEFF/, // Byte order mark |
| 52 | + /\u00AD/, // Soft-hyphen |
| 53 | + /[\uD800-\uDFFF\uE000-\uF8FF\uFFF0-\uFFFF]/, // Surrogates, Private Use Area and Specials, including the Replacement Character U+FFFD |
| 54 | + /[^\0-\uFFFF]/, // Very few characters outside the Basic Multilingual Plane are useful in titles |
| 55 | + /''/ |
| 56 | + ], |
| 57 | + |
| 58 | + // note lack of extension, since we test title without extension. |
| 59 | + 'titleSenselessimagename': [ |
| 60 | + /^DCP[\d\s]+$/i, // Kodak |
| 61 | + /^DSC.[\d\s]+$/i, // [[w:Design rule for Camera File system]] (Nikon, Fuji, Polaroid) |
| 62 | + /^MVC-?[\d\s]+$/i, // Sony Mavica |
| 63 | + /^P[\dA-F][\d\s]+$/, // Olympus, Kodak |
| 64 | + /^I?MG[P_]?[\d\s]+$/, // Canon, Pentax |
| 65 | + /^1\d+-\d+(_IMG)?$/, // Canon |
| 66 | + /^(IM|EX)[\d\s]+$/, // HP Photosmart |
| 67 | + /^DC[\d\s]+[SML]$/, // Kodak |
| 68 | + /^PIC[T_]?[\d\s]+$/, // Minolta |
| 69 | + /^PANA[\d\s]+$/, // Panasonic |
| 70 | + /^DUW[\d\s]+$/, // some mobile phones |
| 71 | + /^CIMG[\d\s]+$/, // Casio |
| 72 | + /^JD[\d\s]+$/, // Jenoptik |
| 73 | + /^SDC[\d\s]+$/, // Samsung |
| 74 | + /^DVC[\d\s]+$/, // DoCoMo |
| 75 | + /^SANY[\d\s]+$/, // Sanyo |
| 76 | + ], |
| 77 | + |
| 78 | + // filename from elsewhere |
| 79 | + 'titleHosting': [ |
| 80 | + /\d{9}[A-Z]{6}_[A-Z]{2}[^A-Za-z]*/, // some image hosting site? |
| 81 | + /\d{8,}_[\dA-F]{10}(_[A-Z])?[^A-Za-z]*/i, // http://www.flickr.com/services/api/misc.urls.html/i, |
| 82 | + /([\dA-F]{8}-)?[\dA-F]{4}-[\dA-F]{4}-[\dA-F]{4}-?[\dA-F]{12}.*/, // [[w:UUID]] (with some variations included) |
| 83 | + /([SML]|\d+)_[\dA-F]{10,}(-\d+-|_?(\w\w?|full))?/, // L_9173c67eae58edc35ba7f2df08a7d5c6.jpg, 2421601587_abaf4e3e81.jpg, 1_bf38bcd9c5512a5ab99ca2219a4b1e2f_full.gif, etc. |
| 84 | + /AT[AEIMQUYcgkosw048]AAA[A-D][-_A-Za-z0-9]+/, // see Commons:Village pump#File ATgAAA... (Jan 20, 2009, full link in edit comment) |
| 85 | + /(\d+_){2,}[qtsn]/, // Facebook: \d+_\d+_(\d+)_(\d+)_\d+_[qtsn]\.jpg -> photo.php?id=$1&pid=$2 |
| 86 | + /[qtsn]\d+(_\d+)+/, // Facebook (older?): [qtsn](\d+)_(\d+)_\d+\.jpg -> photo.php?id=$1&pid=$2 |
| 87 | + /^Tumblr_[a-z\d]{19}_\d+\.w+/, // Tumblr |
| 88 | + /^File$/, |
| 89 | + /^[^A-Za-z]*(small|medium|large)\)?/, |
| 90 | + /^(Untitled|No[-_]?name|Picture|Pict?|Image[mn]?|Img|Immagine|Photo|Foto|Bild|Scan|Panorama|Sin_título)[^A-Za-z]*/, |
| 91 | + /^(January|Jan|February|Febr?|March|Mar|April|Apr|May|June?|July?|August|Aug|September|Sept?|October|Oct|November|Nov|December|Dec)[^A-Za-z]*/, |
| 92 | + /^[0-9 ]*([A-Z][0-9 ]*){30,}/, |
| 93 | + ], |
| 94 | + |
| 95 | + 'titleThumbnail': [ |
| 96 | + /^\d+px-.*/ |
| 97 | + ] |
| 98 | + |
| 99 | + }; |
| 100 | + |
| 101 | + $j.each( regexSets, function( name, regexes ) { |
| 102 | + var tester = ( function( regexes ) { |
| 103 | + return function( value, element, params ) { |
| 104 | + var ok = true; |
| 105 | + $.each( regexes, function( i, regex ) { |
| 106 | + if ( value.match( regex ) ) { |
| 107 | + ok = false; |
| 108 | + return false; |
| 109 | + } |
| 110 | + } ); |
| 111 | + return ok; |
| 112 | + }; |
| 113 | + } )( regexes ); |
| 114 | + $.validator.addMethod( name, tester, "This title is not allowed" ); |
| 115 | + } ); |
| 116 | + |
| 117 | + |
| 118 | +} )( jQuery ); |
Property changes on: trunk/extensions/UploadWizard/resources/jquery/jquery.validate.wmCommonsBlacklist.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 119 | + native |
Index: trunk/extensions/UploadWizard/resources/uploadWizard.css |
— | — | @@ -597,12 +597,12 @@ |
598 | 598 | cursor: pointer; |
599 | 599 | } |
600 | 600 | |
601 | | -.mwe-error, .mwe-validator-error { |
| 601 | +.mwe-error, .mwe-validator-error, .errorTitleUnique { |
602 | 602 | color: #ff0000; |
603 | 603 | } |
604 | 604 | |
605 | 605 | .mwe-upwiz-deed-thirdparty .mwe-upwiz-deed-form-internal label.mwe-error, |
606 | | -.mwe-upwiz-deed-thirdparty .mwe-upwiz-deed-form-internal label.mwe-validator-error { |
| 606 | +.mwe-upwiz-deed-thirdparty .mwe-upwiz-deed-form-internal label.mwe-validator-error, label.errorTitleUnique { |
607 | 607 | margin-left: 0; |
608 | 608 | } |
609 | 609 | |
Index: trunk/extensions/UploadWizard/resources/mw.UploadWizardDetails.js |
— | — | @@ -1,4 +1,3 @@ |
2 | | - |
3 | 2 | /** |
4 | 3 | * Object that represents the Details (step 2) portion of the UploadWizard |
5 | 4 | * n.b. each upload gets its own details. |
— | — | @@ -62,7 +61,10 @@ |
63 | 62 | processResult: function( result ) { _this.processDestinationCheck( result ); } |
64 | 63 | } ); |
65 | 64 | |
66 | | - _this.titleErrorDiv = $j('<div class="mwe-upwiz-details-input-error"><label class="mwe-validator-error" for="' + _this.titleId + '" generated="true"/></div>'); |
| 65 | + _this.titleErrorDiv = $j('<div class="mwe-upwiz-details-input-error">' |
| 66 | + + '<label class="mwe-validator-error" for="' + _this.titleId + '" generated="true"/>' |
| 67 | + + '<label class="errorTitleUnique" for="' + _this.titleId + '" generated="true"/>' |
| 68 | + + '</div>'); |
67 | 69 | |
68 | 70 | var titleHintId = 'mwe-upwiz-title-hint-' + _this.upload.index; |
69 | 71 | var $titleDialog = $('<div>') |
— | — | @@ -229,12 +231,22 @@ |
230 | 232 | _this.addDescription( true, mw.config.get( 'wgUserLanguage' ) ); |
231 | 233 | $j( containerDiv ).append( _this.div ); |
232 | 234 | |
233 | | - // make the title field required |
| 235 | + // make the title field required, and non-blacklisted |
234 | 236 | _this.$form.find( '.mwe-title' ) |
235 | 237 | .rules( "add", { |
236 | 238 | required: true, |
| 239 | + titleBlacklist: true, |
| 240 | + titleBadchars: true, |
| 241 | + titleSenselessimagename: true, |
| 242 | + titleHosting: true, |
| 243 | + titleThumbnail: true, |
237 | 244 | messages: { |
238 | | - required: gM( 'mwe-upwiz-error-blank' ) |
| 245 | + required: gM( 'mwe-upwiz-error-blank' ), |
| 246 | + titleBlacklist: gM( 'mwe-upwiz-error-title-blacklisted' ), |
| 247 | + titleBadchars: gM( 'mwe-upwiz-error-title-badchars' ), |
| 248 | + titleSenselessimagename: gM( 'mwe-upwiz-error-title-senselessimagename' ), |
| 249 | + titleHosting: gM( 'mwe-upwiz-error-title-hosting' ), |
| 250 | + titleThumbnail: gM( 'mwe-upwiz-error-title-thumbnail' ) |
239 | 251 | } |
240 | 252 | } ); |
241 | 253 | |
— | — | @@ -323,9 +335,11 @@ |
324 | 336 | */ |
325 | 337 | processDestinationCheck: function( result ) { |
326 | 338 | var _this = this; |
| 339 | + var $errorEl = _this.$form.find( 'label[for=' + _this.titleId + '].errorTitleUnique' ); |
| 340 | + |
327 | 341 | if ( result.isUnique ) { |
328 | 342 | $j( _this.titleInput ).data( 'valid', true ); |
329 | | - _this.$form.find( 'label[for=' + _this.titleId + ']' ).hide().empty(); |
| 343 | + $errorEl.hide().empty(); |
330 | 344 | _this.ignoreWarningsInput = undefined; |
331 | 345 | return; |
332 | 346 | } |
— | — | @@ -348,9 +362,7 @@ |
349 | 363 | errHtml = gM( 'mwe-upwiz-fileexists-replace-no-link', titleString ); |
350 | 364 | } |
351 | 365 | |
352 | | - _this.$form.find( 'label[for=' + _this.titleId + ']' ) |
353 | | - .html( errHtml ) |
354 | | - .show(); |
| 366 | + $errorEl.html( errHtml ).show(); |
355 | 367 | }, |
356 | 368 | |
357 | 369 | /** |