Implemented cover photo upload and deletion
authorAlexander Ebert <ebert@woltlab.com>
Tue, 28 Nov 2017 19:37:26 +0000 (20:37 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 28 Nov 2017 19:37:33 +0000 (20:37 +0100)
See #2484

13 files changed:
com.woltlab.wcf/templates/user.tpl
com.woltlab.wcf/userGroupOption.xml
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/CoverPhoto/Delete.js [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/CoverPhoto/Upload.js [new file with mode: 0644]
wcfsetup/install/files/lib/data/user/UserProfileAction.class.php
wcfsetup/install/files/lib/data/user/cover/photo/DefaultUserCoverPhoto.class.php
wcfsetup/install/files/lib/data/user/cover/photo/IUserCoverPhoto.class.php
wcfsetup/install/files/lib/data/user/cover/photo/UserCoverPhoto.class.php
wcfsetup/install/files/lib/system/upload/UserCoverPhotoUploadFileValidationStrategy.class.php [new file with mode: 0644]
wcfsetup/install/files/style/ui/userProfile.scss
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index df335ebee2e24374de3c09fbf8082c9a260ce916..91ddf303f1824924d5041d80ab2a204e2cad46ec 100644 (file)
                {/if}>
                {if MODULE_USER_COVER_PHOTO}
                        <div class="userProfileCoverPhoto" style="background-image: url({$user->getCoverPhoto()->getURL()})">
-                               {if $user->userID == $__wcf->user->userID}<a href="#" class="button small jsButtonEditCoverPhoto"><span class="icon icon16 fa-pencil"></span> {lang}wcf.user.coverPhoto.edit{/lang}</a>{/if}
+                               {if $user->userID == $__wcf->user->userID && ($__wcf->getSession()->getPermission('user.profile.coverPhoto.canUploadCoverPhoto') || $user->coverPhotoHash)}
+                                       <div class="userProfileManageCoverPhoto dropdown jsOnly">
+                                               <a href="#" class="button small dropdownToggle"><span class="icon icon16 fa-pencil"></span> {lang}wcf.user.coverPhoto.edit{/lang}</a>
+                                               <ul class="dropdownMenu">
+                                                       {if $__wcf->getSession()->getPermission('user.profile.coverPhoto.canUploadCoverPhoto')}
+                                                               <li><a href="#" class="jsButtonUploadCoverPhoto jsStaticDialog" data-dialog-id="userProfileCoverPhotoUpload">{lang}wcf.user.coverPhoto.upload{/lang}</a></li>
+                                                       {/if}
+                                                       <li><a href="#" class="jsButtonDeleteCoverPhoto"{if !$user->coverPhotoHash} style="display:none;"{/if}>{lang}wcf.user.coverPhoto.delete{/lang}</a></li>
+                                               </ul>
+                                       </div>
+                               {/if}
                        </div>
                {/if}
                <div class="contentHeaderIcon">
        <p class="info">{lang}wcf.user.profile.protected{/lang}</p>
 {/if}
 
+{if MODULE_USER_COVER_PHOTO && $user->userID == $__wcf->user->userID}
+       {if $__wcf->getSession()->getPermission('user.profile.coverPhoto.canUploadCoverPhoto')}
+               <div id="userProfileCoverPhotoUpload" class="jsStaticDialogContent" data-title="{lang}wcf.user.coverPhoto.upload{/lang}">
+                       {lang}wcf.user.coverPhoto.description{/lang}
+                       
+                       {if $__wcf->user->disableCoverPhoto}
+                               <p class="error">{lang}wcf.user.coverPhoto.error.disabled{/lang}</p>
+                       {else}
+                               <div id="coverPhotoUploadPreview"></div>
+                               
+                               {* placeholder for the upload button *}
+                               <div id="coverPhotoUploadButtonContainer"></div>
+                       {/if}
+               </div>
+               <script data-relocate="true">
+                       require(['Language', 'WoltLabSuite/Core/Ui/User/CoverPhoto/Upload'], function (Language, UiUserCoverPhotoUpload) {
+                               Language.addObject({
+                                       'wcf.user.coverPhoto.upload.error.invalidExtension': '{lang}wcf.user.coverPhoto.upload.error.invalidExtension{/lang}',
+                                       'wcf.user.coverPhoto.upload.error.tooSmall': '{lang}wcf.user.coverPhoto.upload.error.tooSmall{/lang}',
+                                       'wcf.user.coverPhoto.upload.error.tooLarge': '{lang}wcf.user.coverPhoto.upload.error.tooLarge{/lang}',
+                                       'wcf.user.coverPhoto.upload.error.uploadFailed': '{lang}wcf.user.coverPhoto.upload.error.uploadFailed{/lang}',
+                                       'wcf.user.coverPhoto.upload.error.badImage': '{lang}wcf.user.coverPhoto.upload.error.badImage{/lang}',
+                                       'wcf.user.coverPhoto.upload.success': '{lang}wcf.user.coverPhoto.upload.success{/lang}'
+                               });
+                               
+                               {if !$__wcf->user->disableCoverPhoto}
+                                       new UiUserCoverPhotoUpload();
+                               {/if}
+                       });
+               </script>
+       {/if}
+       <script data-relocate="true">
+               require(['WoltLabSuite/Core/Ui/User/CoverPhoto/Delete'], function (UiUserCoverPhotoDelete) {
+                       UiUserCoverPhotoDelete.init();
+               })
+       </script>
+{/if}
+
 {include file='footer'}
index d36f53aaa9b5cab89f7fc4bbe9b44bb6859644c1..f695d11524542e70872ea7af78a61888f540c30b 100644 (file)
@@ -749,6 +749,13 @@ png</defaultvalue>
                                <defaultvalue>1</defaultvalue>
                                <usersonly>1</usersonly>
                        </option>
+                       <option name="user.profile.coverPhoto.maxSize">
+                               <categoryname>user.profile.coverPhoto</categoryname>
+                               <optiontype>fileSize</optiontype>
+                               <defaultvalue>500000</defaultvalue>
+                               <minvalue>100000</minvalue>
+                               <usersonly>1</usersonly>
+                       </option>
                        
                        <option name="user.profile.trophy.canSeeTrophies">
                                <categoryname>user.profile.trophy</categoryname>
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/CoverPhoto/Delete.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/CoverPhoto/Delete.js
new file mode 100644 (file)
index 0000000..2ccaf76
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Deletes the current user cover photo.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLabSuite/Core/Ui/User/CoverPhoto/Delete
+ */
+define(['Ajax', 'EventHandler', 'Language', 'Ui/Confirmation', 'Ui/Notification'], function (Ajax, EventHandler, Language, UiConfirmation, UiNotification) {
+       "use strict";
+       
+       var _button;
+       
+       /**
+        * @exports     WoltLabSuite/Core/Ui/User/CoverPhoto/Delete
+        */
+       return {
+               /**
+                * Initializes the delete handler and enables the delete button on upload.
+                */
+               init: function () {
+                       _button = elBySel('.jsButtonDeleteCoverPhoto');
+                       _button.addEventListener(WCF_CLICK_EVENT, this._click.bind(this));
+                       
+                       EventHandler.add('com.woltlab.wcf.user', 'coverPhoto', function (data) {
+                               if (typeof data.url === 'string' && data.url.length > 0) {
+                                       elShow(_button.parentNode);
+                               }
+                       });
+               },
+               
+               /**
+                * Handles clicks on the delete button.
+                * 
+                * @protected
+                */
+               _click: function () {
+                       UiConfirmation.show({
+                               confirm: Ajax.api.bind(Ajax, this),
+                               message: Language.get('wcf.user.coverPhoto.delete.confirmMessage')
+                       });
+               },
+               
+               _ajaxSuccess: function (data) {
+                       elBySel('.userProfileCoverPhoto').style.setProperty('background-image', 'url(' + data.returnValues.url + ')', '');
+                       
+                       elHide(_button.parentNode);
+                       
+                       UiNotification.show();
+               },
+               
+               _ajaxSetup: function () {
+                       return {
+                               data: {
+                                       actionName: 'deleteCoverPhoto',
+                                       className: 'wcf\\data\\user\\UserProfileAction'
+                               }
+                       };
+               }
+       };
+});
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/CoverPhoto/Upload.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/CoverPhoto/Upload.js
new file mode 100644 (file)
index 0000000..d7aa58b
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Uploads the user cover photo via AJAX.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLabSuite/Core/Ui/User/CoverPhoto/Upload
+ */
+define(['Core', 'EventHandler', 'Upload', 'Ui/Notification', 'Ui/Dialog'], function(Core, EventHandler, Upload, UiNotification, UiDialog) {
+       "use strict";
+       
+       /**
+        * @constructor
+        */
+       function UiUserCoverPhotoUpload() {
+               Upload.call(this, 'coverPhotoUploadButtonContainer', 'coverPhotoUploadPreview', {
+                       action: 'uploadCoverPhoto',
+                       className: 'wcf\\data\\user\\UserProfileAction'
+               });
+       }
+       Core.inherit(UiUserCoverPhotoUpload, Upload, {
+               /**
+                * @see WoltLabSuite/Core/Upload#_success
+                */
+               _success: function(uploadId, data) {
+                       // remove or display the error message
+                       elInnerError(this._button, data.returnValues.errorMessage);
+                       
+                       // remove the upload progress
+                       this._target.innerHTML = '';
+                       
+                       if (data.returnValues.url) {
+                               elBySel('.userProfileCoverPhoto').style.setProperty('background-image', 'url(' + data.returnValues.url + ')', '');
+                               
+                               UiDialog.close('userProfileCoverPhotoUpload');
+                               UiNotification.show();
+                               
+                               EventHandler.fire('com.woltlab.wcf.user', 'coverPhoto', {
+                                       url: data.returnValues.url
+                               });
+                       }
+               }
+       });
+       
+       return UiUserCoverPhotoUpload;
+});
index 39e22fc1f91a2be47d0cb4197097e8fe2854aa43..10996d3b197ef236f12eaaeff3d3af3c1b7f05d2 100644 (file)
@@ -11,10 +11,14 @@ use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\html\output\HtmlOutputProcessor;
 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
 use wcf\system\option\user\UserOptionHandler;
+use wcf\system\upload\UploadFile;
+use wcf\system\upload\UploadHandler;
+use wcf\system\upload\UserCoverPhotoUploadFileValidationStrategy;
 use wcf\system\user\group\assignment\UserGroupAssignmentHandler;
 use wcf\system\user\storage\UserStorageHandler;
 use wcf\system\WCF;
 use wcf\util\ArrayUtil;
+use wcf\util\FileUtil;
 use wcf\util\MessageUtil;
 use wcf\util\StringUtil;
 
@@ -36,7 +40,13 @@ class UserProfileAction extends UserAction {
         * user profile object
         * @var UserProfile
         */
-       public $userProfile = null;
+       public $userProfile;
+       
+       /**
+        * uploaded file
+        * @var UploadFile
+        */
+       public $uploadFile;
        
        /**
         * Validates parameters for signature preview.
@@ -467,6 +477,112 @@ class UserProfileAction extends UserAction {
                }
        }
        
+       /**
+        * Validates the 'uploadCoverPhoto' method.
+        *
+        * @throws      PermissionDeniedException
+        * @throws      UserInputException
+        * @since       3.1
+        */
+       public function validateUploadCoverPhoto() {
+               if (!MODULE_USER_COVER_PHOTO) {
+                       throw new PermissionDeniedException();
+               }
+               
+               WCF::getSession()->checkPermissions(['user.profile.coverPhoto.canUploadCoverPhoto']);
+               
+               // validate uploaded file
+               if (!isset($this->parameters['__files']) || count($this->parameters['__files']->getFiles()) != 1) {
+                       throw new UserInputException('files');
+               }
+               
+               /** @var UploadHandler $uploadHandler */
+               $uploadHandler = $this->parameters['__files'];
+               
+               $this->uploadFile = $uploadHandler->getFiles()[0];
+               
+               $uploadHandler->validateFiles(new UserCoverPhotoUploadFileValidationStrategy());
+       }
+       
+       /**
+        * Uploads a cover photo.
+        * 
+        * @since       3.1
+        */
+       public function uploadCoverPhoto() {
+               if ($this->uploadFile->getValidationErrorType()) {
+                       return [
+                               'filesize' => $this->uploadFile->getFilesize(),
+                               'errorMessage' => WCF::getLanguage()->getDynamicVariable('wcf.user.coverPhoto.upload.error.' . $this->uploadFile->getValidationErrorType(), [
+                                       'file' => $this->uploadFile
+                               ]),
+                               'errorType' => $this->uploadFile->getValidationErrorType()
+                       ];
+               }
+               
+               // delete old cover photo
+               if (WCF::getUser()->coverPhotoHash) {
+                       UserProfileRuntimeCache::getInstance()->getObject(WCF::getUser()->userID)->getCoverPhoto()->delete();
+               }
+               
+               // update user
+               (new UserEditor(WCF::getUser()))->update([
+                       // always generate a new hash to invalidate the browser cache and to avoid filename guessing
+                       'coverPhotoHash' => StringUtil::getRandomID(),
+                       'coverPhotoExtension' => $this->uploadFile->getFileExtension()
+               ]);
+               
+               // force-reload the user profile to use a predictable code-path to fetch the cover photo
+               UserProfileRuntimeCache::getInstance()->removeObject(WCF::getUser()->userID);
+               $userProfile = UserProfileRuntimeCache::getInstance()->getObject(WCF::getUser()->userID);
+               $coverPhoto = $userProfile->getCoverPhoto();
+               
+               // check images directory and create subdirectory if necessary
+               $dir = dirname($coverPhoto->getLocation());
+               if (!@file_exists($dir)) {
+                       FileUtil::makePath($dir);
+               }
+               
+               if (@move_uploaded_file($this->uploadFile->getLocation(), $coverPhoto->getLocation())) {
+                       return [
+                               'url' => $coverPhoto->getURL()
+                       ];
+               }
+               else {
+                       return [
+                               'filesize' => $this->uploadFile->getFilesize(),
+                               'errorMessage' => WCF::getLanguage()->getDynamicVariable('wcf.user.coverPhoto.upload.error.uploadFailed', [
+                                       'file' => $this->uploadFile
+                               ]),
+                               'errorType' => 'uploadFailed'
+                       ];
+               }
+       }
+       
+       public function validateDeleteCoverPhoto() {
+               if (!MODULE_USER_COVER_PHOTO) {
+                       throw new PermissionDeniedException();
+               }
+       }
+       
+       public function deleteCoverPhoto() {
+               if (WCF::getUser()->coverPhotoHash) {
+                       UserProfileRuntimeCache::getInstance()->getObject(WCF::getUser()->userID)->getCoverPhoto()->delete();
+                       
+                       (new UserEditor(WCF::getUser()))->update([
+                               'coverPhotoHash' => null,
+                               'coverPhotoExtension' => ''
+                       ]);
+               }
+               
+               // force-reload the user profile to use a predictable code-path to fetch the cover photo
+               UserProfileRuntimeCache::getInstance()->removeObject(WCF::getUser()->userID);
+               
+               return [
+                       'url' => UserProfileRuntimeCache::getInstance()->getObject(WCF::getUser()->userID)->getCoverPhoto()->getURL()
+               ];
+       }
+       
        /**
         * Returns the user option handler object.
         * 
index 318bf196d86c5af7e83efab5e8f92392de99403d..a5e8ea7154a920dc78a20e29a49aa48399e80f8e 100644 (file)
@@ -12,6 +12,13 @@ use wcf\system\WCF;
  * @package    WoltLabSuite\Core\Data\User\Cover\Photo
  */
 class DefaultUserCoverPhoto implements IUserCoverPhoto {
+       /**
+        * @inheritDoc
+        */
+       public function delete() {
+               /* NOP */
+       }
+       
        /**
         * @inheritDoc
         */
index 4a207f80837700dc57e16390f11f2136e61bb943..3687e069f36a3079e265310e98dd3e65eb7571b9 100644 (file)
@@ -10,6 +10,10 @@ namespace wcf\data\user\cover\photo;
  * @package    WoltLabSuite\Core\Data\User\Cover\Photo
  */
 interface IUserCoverPhoto {
+       /**
+        * Deletes this cover photo.
+        */
+       public function delete();
        
        /**
         * Returns the physical location of this cover photo.
index d7b6868923eb4a70933c6870d7442f1a638fe313..fb118d4429261499f337595c2fc07db57fa27b32 100644 (file)
@@ -47,6 +47,15 @@ class UserCoverPhoto implements IUserCoverPhoto {
                $this->coverPhotoExtension = $coverPhotoExtension;
        }
        
+       /**
+        * @inheritDoc
+        */
+       public function delete() {
+               if (file_exists($this->getLocation())) {
+                       @unlink($this->getLocation());
+               }
+       }
+       
        /**
         * @inheritDoc
         */
diff --git a/wcfsetup/install/files/lib/system/upload/UserCoverPhotoUploadFileValidationStrategy.class.php b/wcfsetup/install/files/lib/system/upload/UserCoverPhotoUploadFileValidationStrategy.class.php
new file mode 100644 (file)
index 0000000..86d85d5
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+namespace wcf\system\upload;
+use wcf\data\user\cover\photo\UserCoverPhoto;
+use wcf\system\WCF;
+use wcf\util\ExifUtil;
+use wcf\util\FileUtil;
+
+/**
+ * Upload file validation strategy implementation for user cover photos.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Gallery\System\Upload
+ * @since      3.1
+ */
+class UserCoverPhotoUploadFileValidationStrategy implements IUploadFileValidationStrategy {
+       /**
+        * list of allowed file extensions
+        * @var string[]
+        */
+       public static $allowedExtensions = ['gif', 'jpg', 'jpeg', 'png'];
+       
+       /**
+        * @inheritDoc
+        */
+       public function validate(UploadFile $uploadFile) {
+               if ($uploadFile->getErrorCode() != 0) {
+                       $uploadFile->setValidationErrorType('uploadFailed');
+                       
+                       return false;
+               }
+               
+               // validate file extension
+               if (!in_array($uploadFile->getFileExtension(), self::$allowedExtensions)) {
+                       $uploadFile->setValidationErrorType('fileExtension');
+                       
+                       return false;
+               }
+               
+               // check image data
+               $imageData = $uploadFile->getImageData();
+               if ($imageData === null) {
+                       $uploadFile->setValidationErrorType('noImage');
+                       
+                       return false;
+               }
+               
+               $height = $imageData['height'];
+               $width = $imageData['width'];
+               $orientation = ExifUtil::getOrientation(ExifUtil::getExifData($uploadFile->getLocation()));
+               
+               // flip height and width if image is rotated 90 or 270 degrees
+               if ($orientation == ExifUtil::ORIENTATION_90_ROTATE || $orientation == ExifUtil::ORIENTATION_270_ROTATE) {
+                       $height = $imageData['width'];
+                       $width = $imageData['height'];
+               }
+               
+               // estimate if there is enough memory for a resize, if there is,
+               // we do not need to mark an image which is too high or too wide
+               // as invalid
+               $sufficientMemory = FileUtil::checkMemoryLimit($width * $height * ($uploadFile->getFileExtension() == 'png' ? 4 : 3) * 2.1);
+               
+               // check width
+               if ($width < UserCoverPhoto::MIN_WIDTH) {
+                       $uploadFile->setValidationErrorType('minWidth');
+                       
+                       return false;
+               }
+               else if (!$sufficientMemory && $width > UserCoverPhoto::MAX_WIDTH) {
+                       $uploadFile->setValidationErrorType('maxWidth');
+                       
+                       return false;
+               }
+               
+               // check height
+               if ($height < UserCoverPhoto::MIN_HEIGHT) {
+                       $uploadFile->setValidationErrorType('minHeight');
+                       
+                       return false;
+               }
+               else if (!$sufficientMemory && $height > UserCoverPhoto::MAX_HEIGHT) {
+                       $uploadFile->setValidationErrorType('maxHeight');
+                       
+                       return false;
+               }
+               
+               // check file size if image will not be resized automatically
+               // the file size of resized images is checked in ImageAction::processImages() 
+               $filesize = $uploadFile->getFilesize();
+               if ($width <= UserCoverPhoto::MAX_WIDTH && $height <= UserCoverPhoto::MAX_HEIGHT) {
+                       if ($filesize > WCF::getSession()->getPermission('user.profile.coverPhoto.maxSize')) {
+                               $uploadFile->setValidationErrorType('maxSize');
+                               
+                               return false;
+                       }
+               }
+               
+               return true;
+       }
+}
index d4fde7af557eaaaf6fceb88b96cbf6c504b4f30c..e0faa27e37a54fa28316f450a1b98ad6c0e6f139 100644 (file)
                        top: 0;
                }
                
-               .jsButtonEditCoverPhoto {
+               .userProfileManageCoverPhoto {
                        position: absolute;
                        right: 10px;
                        top: 10px;
index a4776ce42287daa030a1aad4dd647143847b00d6..fb12ba8447a3509c131d0adc7e99b3695e21a401 100644 (file)
@@ -3928,7 +3928,18 @@ Die E-Mail-Adresse des neuen Benutzers lautet: {@$user->email}
        </category>
        
        <category name="wcf.user.coverPhoto">
+               <item name="wcf.user.coverPhoto.delete"><![CDATA[Profilbild löschen]]></item>
+               <item name="wcf.user.coverPhoto.delete.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du dein{else}Wollen Sie Ihr{/if} Profilbild wirklich löschen? Nach dem Löschen wird wieder das Standard-Bild angezeigt.]]></item>
                <item name="wcf.user.coverPhoto.edit"><![CDATA[Profilbild bearbeiten]]></item>
+               <item name="wcf.user.coverPhoto.upload"><![CDATA[Profilbild hochladen]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.badImage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} kein gültiges Bild hochgeladen.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.invalidExtension"><![CDATA[Die Datei hat eine ungültige Dateiendung.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.maxHeight"><![CDATA[Das Bild ist zu hoch.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.maxSize"><![CDATA[Die Datei ist zu groß.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.maxWidth"><![CDATA[Das Bild ist zu breit.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.minHeight"><![CDATA[Das Bild ist zu niedrig.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.minWidth"><![CDATA[Das Bild ist zu schmal.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.uploadFailed"><![CDATA[Beim Hochladen der Datei ist ein unbekannter Fehler aufgetreten.]]></item>
        </category>
        
        <category name="wcf.user.notification">
index e1df272b26cd1208a3d5b0b760d5368f2da2a309..7ee19d51080ccf5490613bd9eb28fbe5a36bc401 100644 (file)
@@ -3920,7 +3920,18 @@ Open the link below to access the user profile:
        </category>
        
        <category name="wcf.user.coverPhoto">
+               <item name="wcf.user.coverPhoto.delete"><![CDATA[Delete Cover Photo]]></item>
+               <item name="wcf.user.coverPhoto.delete.confirmMessage"><![CDATA[Do you really want to delete your cover photo? This will replace your current photo with the default image.]]></item>
                <item name="wcf.user.coverPhoto.edit"><![CDATA[Edit Cover Photo]]></item>
+               <item name="wcf.user.coverPhoto.upload"><![CDATA[Upload Cover Photo]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.badImage"><![CDATA[The uploaded file is not an image.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.invalidExtension"><![CDATA[The file has an invalid extension.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.maxHeight"><![CDATA[The image is too tall.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.maxSize"><![CDATA[The file is too big.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.maxWidth"><![CDATA[The image is too wide.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.minHeight"><![CDATA[The image is too small.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.minWidth"><![CDATA[The image is too small.]]></item>
+               <item name="wcf.user.coverPhoto.upload.error.uploadFailed"><![CDATA[An unknown error occurred during the upload.]]></item>
        </category>
        
        <category name="wcf.user.notification">
index c43251aa221b5c4f6ce1de6dbb1b4aff74a5a40e..a6079a06c5254be76e6d4e72cc1a40a6b88c0ae2 100644 (file)
@@ -1426,6 +1426,10 @@ CREATE TABLE wcf1_user (
        authData VARCHAR(191) NOT NULL DEFAULT '',
        likesReceived MEDIUMINT(7) NOT NULL DEFAULT 0,
        trophyPoints INT(10) NOT NULL DEFAULT 0,
+       coverPhotoHash CHAR(40) DEFAULT NULL,
+       coverPhotoExtension VARCHAR(4) NOT NULL DEFAULT '',
+       disableCoverPhoto TINYINT(1) NOT NULL DEFAULT 0,
+       disableCoverPhotoExpires INT(10) NOT NULL DEFAULT 0,
        
        KEY username (username),
        KEY email (email),