Add user rank image upload
authorjoshuaruesweg <ruesweg@woltlab.com>
Thu, 7 Jan 2021 14:53:15 +0000 (15:53 +0100)
committerjoshuaruesweg <ruesweg@woltlab.com>
Mon, 11 Jan 2021 11:46:03 +0000 (12:46 +0100)
wcfsetup/install/files/acp/templates/userRankAdd.tpl
wcfsetup/install/files/lib/acp/form/UserRankAddForm.class.php
wcfsetup/install/files/lib/acp/form/UserRankEditForm.class.php
wcfsetup/install/files/lib/data/user/rank/UserRank.class.php
wcfsetup/install/files/lib/data/user/rank/UserRankAction.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index 705ab7e79ca561cf6534d1030f3be3e94a1c6663..7f21dfeb505bbd84320c98b5c6bed18ba9c4c55b 100644 (file)
                <dl{if $errorField == 'rankImage'} class="formError"{/if}>
                        <dt><label for="rankImage">{lang}wcf.acp.user.rank.image{/lang}</label></dt>
                        <dd>
-                               <input type="text" id="rankImage" name="rankImage" value="{$rankImage}" class="long">
+                               {@$__wcf->getUploadHandler()->renderField('rankImage')}
                                {if $errorField == 'rankImage'}
                                        <small class="innerError">
-                                               {lang}wcf.acp.user.rank.image.error.{@$errorType}{/lang}
+                                               {if $errorType == 'empty'}
+                                                       {lang}wcf.global.form.error.empty{/lang}
+                                               {else}
+                                                       {lang}wcf.acp.user.rank.image.error.{$errorType}{/lang}
+                                               {/if}
                                        </small>
                                {/if}
-                               <small>{lang}wcf.acp.user.rank.rankImage.description{/lang}</small>
                        </dd>
                </dl>
                
                        </dd>
                </dl>
                
-               {if $action == 'edit' && $rank->rankImage}
-                       <dl>
-                               <dt><label>{lang}wcf.acp.user.rank.currentImage{/lang}</label></dt>
-                               <dd>{@$rank->getImage()}</dd>
-                       </dl>
-               {/if}
-               
                <dl{if $errorField == 'hideTitle'} class="formError"{/if}>
                        <dt></dt>
                        <dd>
index 155a88f83220a6c7a3d3a0bd663b3d571bdafcde..67e7a0d027797667b8fb88d5794df60772462e2c 100644 (file)
@@ -6,6 +6,9 @@ use wcf\data\user\rank\UserRankEditor;
 use wcf\data\user\UserProfile;
 use wcf\form\AbstractForm;
 use wcf\system\exception\UserInputException;
+use wcf\system\file\upload\UploadField;
+use wcf\system\file\upload\UploadFile;
+use wcf\system\file\upload\UploadHandler;
 use wcf\system\language\I18nHandler;
 use wcf\system\Regex;
 use wcf\system\request\LinkHandler;
@@ -67,8 +70,7 @@ class UserRankAddForm extends AbstractForm {
        public $requiredPoints = 0;
        
        /**
-        * path to user rank image
-        * @var string
+        * @deprecated since 5.4
         */
        public $rankImage = '';
        
@@ -109,6 +111,16 @@ class UserRankAddForm extends AbstractForm {
                'custom' /* not a real value */
        ];
        
+       /**
+        * @var UploadFile[]
+        */
+       public $removedRankImages;
+       
+       /**
+        * @var UploadFile|bool
+        */
+       public $rankImageFile;
+       
        /**
         * @inheritDoc
         */
@@ -116,6 +128,19 @@ class UserRankAddForm extends AbstractForm {
                parent::readParameters();
                
                I18nHandler::getInstance()->register('rankTitle');
+               
+               $this->rebuildUploadField();
+       }
+       
+       protected function rebuildUploadField(): void {
+               if (UploadHandler::getInstance()->isRegisteredFieldId('rankImage')) {
+                       UploadHandler::getInstance()->unregisterUploadField('rankImage');
+               }
+               $field = new UploadField('rankImage');
+               $field->setImageOnly(true);
+               $field->setAllowSvgImage(true);
+               $field->maxFiles = 1;
+               UploadHandler::getInstance()->registerUploadField($field);
        }
        
        /**
@@ -131,10 +156,13 @@ class UserRankAddForm extends AbstractForm {
                if (isset($_POST['customCssClassName'])) $this->customCssClassName = StringUtil::trim($_POST['customCssClassName']);
                if (isset($_POST['groupID'])) $this->groupID = intval($_POST['groupID']);
                if (isset($_POST['requiredPoints'])) $this->requiredPoints = intval($_POST['requiredPoints']);
-               if (isset($_POST['rankImage'])) $this->rankImage = StringUtil::trim($_POST['rankImage']);
                if (isset($_POST['repeatImage'])) $this->repeatImage = intval($_POST['repeatImage']);
                if (isset($_POST['requiredGender'])) $this->requiredGender = intval($_POST['requiredGender']);
                if (isset($_POST['hideTitle'])) $this->hideTitle = intval($_POST['hideTitle']);
+               
+               $this->removedRankImages = UploadHandler::getInstance()->getRemovedFiledByFieldId('rankImage');
+               $rankImageFiles = UploadHandler::getInstance()->getFilesByFieldId('rankImage');
+               $this->rankImageFile = reset($rankImageFiles);
        }
        
        /**
@@ -180,7 +208,7 @@ class UserRankAddForm extends AbstractForm {
                        $this->requiredGender = 0;
                }
                
-               if ($this->hideTitle && !$this->rankImage) {
+               if ($this->hideTitle && !$this->rankImageFile) {
                        throw new UserInputException('hideTitle', 'rankImage');
                }
        }
@@ -192,16 +220,18 @@ class UserRankAddForm extends AbstractForm {
                parent::save();
                
                // save label
-               $this->objectAction = new UserRankAction([], 'create', ['data' => array_merge($this->additionalFields, [
-                       'rankTitle' => $this->rankTitle,
-                       'cssClassName' => $this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName,
-                       'groupID' => $this->groupID,
-                       'requiredPoints' => $this->requiredPoints,
-                       'rankImage' => $this->rankImage,
-                       'repeatImage' => $this->repeatImage,
-                       'requiredGender' => $this->requiredGender,
-                       'hideTitle' => ($this->hideTitle ? 1 : 0)
-               ])]);
+               $this->objectAction = new UserRankAction([], 'create', [
+                       'data' => array_merge($this->additionalFields, [
+                               'rankTitle' => $this->rankTitle,
+                               'cssClassName' => $this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName,
+                               'groupID' => $this->groupID,
+                               'requiredPoints' => $this->requiredPoints,
+                               'repeatImage' => $this->repeatImage,
+                               'requiredGender' => $this->requiredGender,
+                               'hideTitle' => ($this->hideTitle ? 1 : 0)
+                       ]), 
+                       'rankImageFile' => $this->rankImageFile,
+               ]);
                $returnValues = $this->objectAction->executeAction();
                $rankID = $returnValues['returnValues']->rankID;
                
@@ -222,6 +252,7 @@ class UserRankAddForm extends AbstractForm {
                $this->repeatImage = 1;
                
                I18nHandler::getInstance()->reset();
+               $this->rebuildUploadField();
                
                // show success message
                WCF::getTPL()->assign([
index 3b41aba6007a21631832f8ff7ab59cccd921a5a9..182fe59223f5d6b079ab010ecbbc675c89901d19 100644 (file)
@@ -4,6 +4,7 @@ use wcf\data\user\rank\UserRank;
 use wcf\data\user\rank\UserRankAction;
 use wcf\form\AbstractForm;
 use wcf\system\exception\IllegalLinkException;
+use wcf\system\file\upload\UploadHandler;
 use wcf\system\language\I18nHandler;
 use wcf\system\WCF;
 
@@ -62,16 +63,19 @@ class UserRankEditForm extends UserRankAddForm {
                }
                
                // update label
-               $this->objectAction = new UserRankAction([$this->rank], 'update', ['data' => array_merge($this->additionalFields, [
-                       'rankTitle' => $this->rankTitle,
-                       'cssClassName' => $this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName,
-                       'groupID' => $this->groupID,
-                       'requiredPoints' => $this->requiredPoints,
-                       'rankImage' => $this->rankImage,
-                       'repeatImage' => $this->repeatImage,
-                       'requiredGender' => $this->requiredGender,
-                       'hideTitle' => $this->hideTitle
-               ])]);
+               $this->objectAction = new UserRankAction([$this->rank], 'update', [
+                       'data' => array_merge($this->additionalFields, [
+                               'rankTitle' => $this->rankTitle,
+                               'cssClassName' => $this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName,
+                               'groupID' => $this->groupID,
+                               'requiredPoints' => $this->requiredPoints,
+                               'repeatImage' => $this->repeatImage,
+                               'requiredGender' => $this->requiredGender,
+                               'hideTitle' => $this->hideTitle
+                       ]),
+                       'rankImageFile' => $this->rankImageFile,
+                       'rankImageFile__removedFiles' => $this->removedRankImages,
+               ]);
                $this->objectAction->executeAction();
                $this->saved();
                
@@ -102,6 +106,12 @@ class UserRankEditForm extends UserRankAddForm {
                        $this->repeatImage = $this->rank->repeatImage;
                        $this->rankImage = $this->rank->rankImage;
                        $this->hideTitle = $this->rank->hideTitle;
+                       
+                       if ($this->rank->getImageFile()) {
+                               UploadHandler::getInstance()->registerFilesByField('rankImage', [
+                                       $this->rank->getImageFile()
+                               ]);
+                       }
                }
        }
        
index 513e4c42598bc84ab351fc3a26f81d5b7c3b8bdb..c22359b0269ffec2eb9f204018caea654fd24232 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\data\user\rank;
 use wcf\data\DatabaseObject;
 use wcf\data\ITitledObject;
+use wcf\system\file\upload\UploadFile;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
 
@@ -24,6 +25,9 @@ use wcf\util\StringUtil;
  * @property-read      integer         $hideTitle              hides the generic title of the rank, but not custom titles, `0` to show the title at all times
  */
 class UserRank extends DatabaseObject implements ITitledObject {
+       
+       public const RANK_IMAGE_DIR = 'images/rank/';
+       
        /**
         * Returns the image of this user rank.
         * 
@@ -31,7 +35,7 @@ class UserRank extends DatabaseObject implements ITitledObject {
         */
        public function getImage() {
                if ($this->rankImage) {
-                       $image = '<img src="'.(!preg_match('~^(/|https?://)~i', $this->rankImage) ? WCF::getPath() : '').StringUtil::encodeHTML($this->rankImage).'" alt="">';
+                       $image = '<img src="'. WCF::getPath() . self::RANK_IMAGE_DIR . StringUtil::encodeHTML($this->rankImage) .'" alt="">';
                        if ($this->repeatImage > 1) $image = str_repeat($image, $this->repeatImage);
                        return $image;
                }
@@ -55,4 +59,17 @@ class UserRank extends DatabaseObject implements ITitledObject {
        public function showTitle() {
                return !$this->rankImage || !$this->hideTitle;
        }
+       
+       /**
+        * Returns the currently uploaded rank image or null, if the rank has no image.
+        *
+        * @since       5.4
+        */
+       public function getImageFile(): ?UploadFile {
+               if ($this->rankImage) {
+                       return new UploadFile(WCF_DIR . self::RANK_IMAGE_DIR . $this->rankImage, $this->rankImage, true, true, true);
+               }
+               
+               return null;
+       }
 }
index 9a75d72b785e37232038be2bff48a0dfb67d9753..686a940dfeb7405b568ad2addf123b6cb3451a90 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 namespace wcf\data\user\rank;
 use wcf\data\AbstractDatabaseObjectAction;
+use wcf\system\exception\InvalidObjectArgument;
+use wcf\system\file\upload\UploadFile;
 
 /**
  * Executes user rank-related actions.
@@ -10,7 +12,6 @@ use wcf\data\AbstractDatabaseObjectAction;
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\User\Rank
  * 
- * @method     UserRank                create()
  * @method     UserRankEditor[]        getObjects()
  * @method     UserRankEditor          getSingleObject()
  */
@@ -24,4 +25,75 @@ class UserRankAction extends AbstractDatabaseObjectAction {
         * @inheritDoc
         */
        protected $requireACP = ['delete'];
+       
+       /**
+        * @inheritDoc
+        */
+       public function create() {
+               /** @var UserRank $rank */
+               $rank = parent::create();
+               
+               if (isset($this->parameters['rankImageFile']) && $this->parameters['rankImageFile']) {
+                       if (!($this->parameters['rankImageFile'] instanceof UploadFile)) {
+                               throw new InvalidObjectArgument($this->parameters['rankImageFile'], UploadFile::class, "The parameter 'rankImageFile'");
+                       }
+                       
+                       if (!$this->parameters['rankImageFile']->isProcessed()) {
+                               $fileName = $rank->rankID . '-' . $this->parameters['rankImageFile']->getFilename();
+                               
+                               rename($this->parameters['rankImageFile']->getLocation(), WCF_DIR . UserRank::RANK_IMAGE_DIR . $fileName);
+                               $this->parameters['rankImageFile']->setProcessed(WCF_DIR . UserRank::RANK_IMAGE_DIR . $fileName);
+                               
+                               $updateData['rankImage'] = $fileName;
+                               
+                               $rankEditor = new UserRankEditor($rank);
+                               $rankEditor->update($updateData);
+                       }
+               }
+               
+               return $rank;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function update() {
+               if (isset($this->parameters['rankImageFile__removedFiles']) && is_array($this->parameters['rankImageFile__removedFiles'])) {
+                       foreach ($this->parameters['rankImageFile__removedFiles'] as $file) {
+                               if (!($file instanceof UploadFile)) {
+                                       throw new InvalidObjectArgument($this->parameters['rankImageFile__removedFiles'], UploadFile::class, "An array values of 'rankImageFile__removedFiles'");
+                               }
+                               
+                               @unlink($file->getLocation());
+                       }
+               }
+               
+               if (isset($this->parameters['rankImageFile'])) {
+                       if (count($this->objects) > 1) {
+                               throw new \BadMethodCallException("The parameter 'rankImageFile' can only be processed, if there is only one object to update.");
+                       }
+                       
+                       $object = reset($this->objects);
+                       
+                       if (!$this->parameters['rankImageFile']) {
+                               $this->parameters['data']['rankImage'] = "";
+                       }
+                       else {
+                               if (!($this->parameters['rankImageFile'] instanceof UploadFile)) {
+                                       throw new InvalidObjectArgument($this->parameters['rankImageFile'], UploadFile::class, "The parameter 'rankImageFile'");
+                               }
+                               
+                               if (!$this->parameters['rankImageFile']->isProcessed()) {
+                                       $fileName = $object->rankID . '-' . $this->parameters['rankImageFile']->getFilename();
+                                       
+                                       rename($this->parameters['rankImageFile']->getLocation(), WCF_DIR . UserRank::RANK_IMAGE_DIR . $fileName);
+                                       $this->parameters['rankImageFile']->setProcessed(WCF_DIR . UserRank::RANK_IMAGE_DIR . $fileName);
+                                       
+                                       $this->parameters['data']['rankImage'] = $fileName;
+                               }
+                       }
+               }
+               
+               parent::update();
+       }
 }
index a220ab02bc2c817fcaa66080c2abeaaeb40d7d08..185fe9e7df08611f4ddda52bb0badbbb98bdb19e 100644 (file)
@@ -3142,7 +3142,6 @@ Wenn {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} unter „Konfiguration 
                <item name="wcf.acp.user.rank.hideTitle.error.rankImage"><![CDATA[Diese Option erfordert eine gültige Ranggrafik.]]></item>
                <item name="wcf.acp.user.rank.image"><![CDATA[Ranggrafik]]></item>
                <item name="wcf.acp.user.rank.list"><![CDATA[Benutzerränge]]></item>
-               <item name="wcf.acp.user.rank.rankImage.description"><![CDATA[Der Pfad zur Ranggrafik kann relativ zum WCF-Verzeichnis oder absolut angegeben werden.]]></item>
                <item name="wcf.acp.user.rank.requiredGender.description"><![CDATA[Optional {if LANGUAGE_USE_INFORMAL_VARIANT}kannst du{else}können Sie{/if} diesen Benutzerrang auf Benutzer mit einem bestimmten Geschlecht einschränken.]]></item>
                <item name="wcf.acp.user.rank.requiredPoints"><![CDATA[Punkte]]></item>
                <item name="wcf.acp.user.rank.requiredPoints.description"><![CDATA[Benötigte Menge an Aktivitätspunkten, die ein Benutzer erreichen muss, um in diesen Rang aufzusteigen.]]></item>
index ac810dfb59cb92030dbda64668126cbd7fb3df8e..4d81f8e35a3a3fcbcb1ec03a1d7793314a8c51d8 100644 (file)
@@ -3070,7 +3070,6 @@ You can define the default sender in “Configuration » Options » General » E
                <item name="wcf.acp.user.rank.hideTitle.error.rankImage"><![CDATA[This option requires a valid rank image.]]></item>
                <item name="wcf.acp.user.rank.image"><![CDATA[Rank Image]]></item>
                <item name="wcf.acp.user.rank.list"><![CDATA[User Ranks]]></item>
-               <item name="wcf.acp.user.rank.rankImage.description"><![CDATA[The path must be either relative to WCF’s directory or absolute.]]></item>
                <item name="wcf.acp.user.rank.requiredGender.description"><![CDATA[The rank can be restricted to a specific gender.]]></item>
                <item name="wcf.acp.user.rank.requiredPoints"><![CDATA[Points]]></item>
                <item name="wcf.acp.user.rank.requiredPoints.description"><![CDATA[The required number of activity points to obtain this rank.]]></item>