Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1432940
UploadJobTrait.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
UploadJobTrait.php
View Options
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @defgroup JobQueue JobQueue
*/
use
MediaWiki\Api\ApiUpload
;
use
MediaWiki\Context\RequestContext
;
use
MediaWiki\Logger\LoggerFactory
;
use
MediaWiki\Status\Status
;
use
MediaWiki\User\User
;
use
Wikimedia\ScopedCallback
;
/**
* Common functionality for async uploads
*
* @ingroup Upload
* @ingroup JobQueue
*/
trait
UploadJobTrait
{
/** @var User|null */
private
$user
;
/** @var string */
private
$cacheKey
;
/** @var UploadBase */
private
$upload
;
/** @var array The job parameters */
public
$params
;
/**
* Set up the job
*
* @param string $cacheKey
* @return void
*/
protected
function
initialiseUploadJob
(
$cacheKey
):
void
{
$this
->
cacheKey
=
$cacheKey
;
$this
->
user
=
null
;
}
/**
* Do not allow retries on jobs by default.
*
* @return bool
*/
public
function
allowRetries
():
bool
{
return
false
;
}
/**
* Run the job
*
* @return bool
*/
public
function
run
():
bool
{
$this
->
user
=
$this
->
getUserFromSession
();
if
(
$this
->
user
===
null
)
{
return
false
;
}
try
{
// Check the initial status of the upload
$startingStatus
=
UploadBase
::
getSessionStatus
(
$this
->
user
,
$this
->
cacheKey
);
// Warn if in wrong stage, but still continue. User may be able to trigger
// this by retrying after failure.
if
(
!
$startingStatus
||
(
$startingStatus
[
'result'
]
??
''
)
!==
'Poll'
||
(
$startingStatus
[
'stage'
]
??
''
)
!==
'queued'
)
{
$logger
=
LoggerFactory
::
getInstance
(
'upload'
);
$logger
->
warning
(
"Tried to publish upload that is in stage {stage}/{result}"
,
$this
->
logJobParams
(
$startingStatus
)
);
}
// Fetch the file if needed
if
(
!
$this
->
fetchFile
()
)
{
return
false
;
}
// Verify the upload is valid
if
(
!
$this
->
verifyUpload
()
)
{
return
false
;
}
// Actually upload the file
if
(
!
$this
->
performUpload
()
)
{
return
false
;
}
// All done
$this
->
setStatusDone
();
// Cleanup any temporary local file
$this
->
getUpload
()->
cleanupTempFile
();
}
catch
(
Exception
$e
)
{
$this
->
setStatus
(
'publish'
,
'Failure'
,
Status
::
newFatal
(
'api-error-publishfailed'
)
);
$this
->
setLastError
(
get_class
(
$e
)
.
": "
.
$e
->
getMessage
()
);
// To prevent potential database referential integrity issues.
// See T34551.
MWExceptionHandler
::
rollbackPrimaryChangesAndLog
(
$e
);
return
false
;
}
return
true
;
}
/**
* Get the cache key used to store status
*
* @return string
*/
public
function
getCacheKey
()
{
return
$this
->
cacheKey
;
}
/**
* Get user data from the session key
*
* @return User|null
*/
private
function
getUserFromSession
()
{
$scope
=
RequestContext
::
importScopedSession
(
$this
->
params
[
'session'
]
);
$this
->
addTeardownCallback
(
static
function
()
use
(
&
$scope
)
{
ScopedCallback
::
consume
(
$scope
);
// T126450
}
);
$context
=
RequestContext
::
getMain
();
$user
=
$context
->
getUser
();
if
(
!
$user
->
isRegistered
()
)
{
$this
->
setLastError
(
"Could not load the author user from session."
);
return
null
;
}
return
$user
;
}
/**
* Set the upload status
*
* @param string $stage
* @param string $result
* @param Status|null $status
* @param array $additionalInfo
*
*/
private
function
setStatus
(
$stage
,
$result
=
'Poll'
,
$status
=
null
,
$additionalInfo
=
[]
)
{
// We're most probably not running in a job.
// @todo maybe throw an exception?
if
(
$this
->
user
===
null
)
{
return
;
}
$status
??=
Status
::
newGood
();
$info
=
[
'result'
=>
$result
,
'stage'
=>
$stage
,
'status'
=>
$status
];
$info
+=
$additionalInfo
;
UploadBase
::
setSessionStatus
(
$this
->
user
,
$this
->
cacheKey
,
$info
);
}
/**
* Ensure we have the file available. A noop here.
*
* @return bool
*/
protected
function
fetchFile
():
bool
{
$this
->
setStatus
(
'fetching'
);
// make sure the upload file is here. This is a noop in most cases.
$status
=
$this
->
getUpload
()->
fetchFile
();
if
(
!
$status
->
isGood
()
)
{
$this
->
setStatus
(
'fetching'
,
'Failure'
,
$status
);
$this
->
setLastError
(
"Error while fetching the image."
);
return
false
;
}
$this
->
setStatus
(
'publish'
);
// We really don't care as this is, as mentioned, generally a noop.
// When that's not the case, classes will need to override this method anyways.
return
true
;
}
/**
* Verify the upload is ok
*
* @return bool
*/
private
function
verifyUpload
():
bool
{
// Check if the local file checks out (this is generally a no-op)
$verification
=
$this
->
getUpload
()->
verifyUpload
();
if
(
$verification
[
'status'
]
!==
UploadBase
::
OK
)
{
$status
=
Status
::
newFatal
(
'verification-error'
);
$status
->
value
=
[
'verification'
=>
$verification
];
$this
->
setStatus
(
'publish'
,
'Failure'
,
$status
);
$this
->
setLastError
(
"Could not verify upload."
);
return
false
;
}
// Verify title permissions for this user
$titleVerification
=
$this
->
getUpload
()->
verifyTitlePermissions
(
$this
->
user
);
if
(
$titleVerification
!==
true
)
{
$this
->
setStatus
(
'publish'
,
'Failure'
,
null
,
$titleVerification
);
$this
->
setLastError
(
"Could not verify title permissions."
);
return
false
;
}
// Verify if any upload warnings are present
$ignoreWarnings
=
$this
->
params
[
'ignorewarnings'
]
??
false
;
$isReupload
=
$this
->
params
[
'reupload'
]
??
false
;
if
(
$ignoreWarnings
)
{
// If we're ignoring warnings, we don't need to check them
return
true
;
}
$warnings
=
$this
->
getUpload
()->
checkWarnings
(
$this
->
user
);
if
(
$warnings
)
{
// If the file exists and we're reuploading, ignore the warning
// and continue with the upload
if
(
count
(
$warnings
)
===
1
&&
isset
(
$warnings
[
'exists'
]
)
&&
$isReupload
)
{
return
true
;
}
// Make the array serializable
$serializableWarnings
=
UploadBase
::
makeWarningsSerializable
(
$warnings
);
$this
->
setStatus
(
'publish'
,
'Warning'
,
null
,
[
'warnings'
=>
$serializableWarnings
]
);
$this
->
setLastError
(
"Upload warnings present."
);
return
false
;
}
return
true
;
}
/**
* Upload the stashed file to a permanent location
*
* @return bool
*/
private
function
performUpload
():
bool
{
if
(
$this
->
user
===
null
)
{
return
false
;
}
$status
=
$this
->
getUpload
()->
performUpload
(
$this
->
params
[
'comment'
],
$this
->
params
[
'text'
],
$this
->
params
[
'watch'
],
$this
->
user
,
$this
->
params
[
'tags'
]
??
[],
$this
->
params
[
'watchlistexpiry'
]
??
null
);
if
(
!
$status
->
isGood
()
)
{
$this
->
setStatus
(
'publish'
,
'Failure'
,
$status
);
$this
->
setLastError
(
$status
->
getWikiText
(
false
,
false
,
'en'
)
);
return
false
;
}
return
true
;
}
/**
* Set the status at the end or processing
*
*/
private
function
setStatusDone
()
{
// Build the image info array while we have the local reference handy
$imageInfo
=
ApiUpload
::
getDummyInstance
()->
getUploadImageInfo
(
$this
->
getUpload
()
);
// Cache the info so the user doesn't have to wait forever to get the final info
$this
->
setStatus
(
'publish'
,
'Success'
,
Status
::
newGood
(),
[
'filename'
=>
$this
->
getUpload
()->
getLocalFile
()->
getName
(),
'imageinfo'
=>
$imageInfo
]
);
}
/**
* Getter for the upload. Needs to be implemented by the job class
*
* @return UploadBase
*/
abstract
protected
function
getUpload
():
UploadBase
;
/**
* Get the job parameters for logging. Needs to be implemented by the job class.
*
* @param Status[] $status
* @return array
*/
abstract
protected
function
logJobParams
(
$status
):
array
;
/**
* This is actually implemented in the Job class
*
* @param mixed $error
* @return void
*/
abstract
protected
function
setLastError
(
$error
);
/**
* This is actually implemented in the Job class
*
* @param callable $callback
* @return void
*/
abstract
protected
function
addTeardownCallback
(
$callback
);
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 22:30 (1 h, 9 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
41/88/1e0c8f7009f57994df931a1841a2
Default Alt Text
UploadJobTrait.php (8 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment