Contao-Camp 2024
Ergebnis 1 bis 17 von 17

Thema: Class \Widget function validator geht nicht mehr

  1. #1
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard Class \Widget function validator geht nicht mehr

    Hallo,

    in Contao 4.13 wird folgende function nicht mehr ausgeführt:

    PHP-Code:
    protected function validator($varInput)
        { 
    diese zum Beispiel geht noch:

    PHP-Code:
    public function validateUpload()
        { 
    weiß jemand was sich da n C4.13 geändert hat? Danke

  2. #2
    Contao-Nutzer
    Registriert seit
    15.03.2010.
    Ort
    AT
    Beiträge
    204

    Standard

    Die war auch in 4.9 schon protected...
    https://github.com/contao/contao/blo...tao/Widget.php

    Vermutlich suchst du validate();

  3. #3
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Danke für die Antwort. Leider wird public function validate() auch nicht ausgeführt.
    Ich teste es mit \System::log
    welche Möglichkeit habe ich noch?
    Die Class wird gerade so erweitert: abstract class AvatarWidgetBase extends \Widget

    Grüße Dennis

  4. #4
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.040
    Partner-ID
    10107

    Standard

    Was genau meinst du mit "nicht ausgeführt"? Was versuchst du zu tun?
    » sponsor me via GitHub or PayPal or Revolut

  5. #5
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Die Avatar Erweiterung wieder fit machen ist das Ziel. Ich nutze diese auch modifiziert, aber das Problem besteht mit der original Version

    PHP-Code:
        protected function validator($varInput)
        {
            
    // Check the mandatoriness
            
    if ($varInput == '' && $this->mandatory) {
                
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['mandatory'], $this->strLabel));
                return 
    '';
            }

            
    $varReturn $varInput;

            
    // Delete the file
            
    if ($varInput == '' && $this->varValue != '') {
                \
    Files::getInstance()->delete($this->varValue);
            }

            
    // Move file to the destination folder
            
    if (is_file(TL_ROOT '/' $varInput) && $this->isTemporaryFile($varInput)) {
                
    $strAvatar = \Avatar::find($this->getId(), $this->getUploadPath());

                
    // Delete the current avatar
                
    if ($strAvatar != '') {
                    \
    Files::getInstance()->delete($strAvatar);
                }

                
    $strNew $this->getUploadPath() . '/' $this->getId() . '-' md5(uniqid(''true)) . '.' pathinfo($varInputPATHINFO_EXTENSION);

                if (\
    Files::getInstance()->rename($varInput$strNew)) {
                    
    $varReturn $strNew;
                }
            }
            \
    System::log('Ein Log-Eintrag2'.$varReturn__CLASS__.'::'.__FUNCTION__TL_GENERAL);
            return 
    $varReturn;
        } 

  6. #6
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.040
    Partner-ID
    10107

    Standard

    Ohne genauer Beschreibung was nun falsch läuft und ohne den gesamten Code zu sehen, wird man wohl nicht viel sagen können. Implementiert denn dein Widget überhaupt das UploadableWidgetInterface (früher einfach nur \uploadable)?
    » sponsor me via GitHub or PayPal or Revolut

  7. #7
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Einmal alles =) in validator wird geprüft ob ein Bild vorliegt und dann von tmp zum Zielverzeichnis verschoben.
    Beim speichern wird aber nichts verschoben und auch der System::log wird nicht ausgeführt

    PHP-Code:
    abstract class AvatarWidgetBase extends \Widget
    {

        
    /**
         * Submit user input
         * @var boolean
         */
        
    protected $blnSubmitInput false;

        
    /**
         * Thumbnail size
         * @var array
         */
        
    protected $arrThumbSize = array();

        
    /**
         * Avatar size
         * @var array
         */
        
    protected $arrAvatarSize = array();

        
    /**
         * Temporary upload path
         * @var string
         */
        
    protected $strTemporaryPath 'system/tmp';

        
    /**
         * Temporary thumbnail path
         * @var string
         */
        
    protected $strThumbnailPath 'assets/images';

        
    /**
         * Load the database object
         * @param array
         */
        
    public function __construct($arrAttributes=null)
        {
            
    parent::__construct($arrAttributes);

            
    $this->arrThumbSize $this->getThumbnailSize();
            
    $this->arrAvatarSize $this->getAvatarSize();

            
    // Include the jQuery
            
    if ($this->addJQuery) {
                if (
    defined('JQUERY')) {
                    
    $GLOBALS['TL_JAVASCRIPT']['jquery'] = 'assets/jquery/core/' JQUERY '/jquery.min.js';
                } else {
                    
    $GLOBALS['TL_JAVASCRIPT']['jquery'] = 'assets/jquery/js/jquery.min.js';
                }
            }
            
    $GLOBALS['TL_JAVASCRIPT']['jquery_noconflict'] = 'system/modules/avatar/assets/jquery-noconflict.min.js';
            
    $GLOBALS['TL_JAVASCRIPT']['avatar_fineuploader'] = 'system/modules/avatar/assets/fineuploader/fineuploader-5.0.2.min.js';
            
    $GLOBALS['TL_JAVASCRIPT']['avatar_jcrop'] = 'system/modules/avatar/assets/Jcrop/js/jquery.Jcrop.min.js';
            
    $GLOBALS['TL_JAVASCRIPT']['avatar_handler'] = 'system/modules/avatar/assets/handler/handler.min.js';
            
    $GLOBALS['TL_CSS']['avatar_jcrop'] = 'system/modules/avatar/assets/Jcrop/css/jquery.Jcrop.min.css';
        }

        
    /**
         * Add specific attributes
         * @param string
         * @param mixed
         */
        
    public function __set($strKey$varValue)
        {
            switch (
    $strKey) {
                case 
    'maxlength':
                    
    // Do not add as attribute (see #3094)
                    
    $this->arrConfiguration['maxlength'] = $varValue;
                    break;

                case 
    'mandatory':
                    if (
    $varValue) {
                        
    $this->arrAttributes['required'] = 'required';
                    } else {
                        unset(
    $this->arrAttributes['required']);
                    }
                    
    parent::__set($strKey$varValue);
                    break;

                default:
                    
    parent::__set($strKey$varValue);
                    break;
            }
        }

        
    /**
         * Validate the upload
         * @return string
         */
        
    public function validateUpload()
        {
            \
    Message::reset();
            
    $strTempName $this->strName '_upload';
            
    $objUploader = new \FileUpload();
            
    $objUploader->setName($this->strName);

            
    // Convert the $_FILES array to Contao format
            
    if (!empty($_FILES[$strTempName])) {
                
    $arrFile = array
                (
                    
    'name' => array($_FILES[$strTempName]['name']),
                    
    'type' => array($_FILES[$strTempName]['type']),
                    
    'tmp_name' => array($_FILES[$strTempName]['tmp_name']),
                    
    'error' => array($_FILES[$strTempName]['error']),
                    
    'size' => array($_FILES[$strTempName]['size']),
                );

                
    // Check if the file exists
                
    if (file_exists(TL_ROOT '/' $this->strTemporaryPath '/' $arrFile['name'][0])) {
                    
    $arrFile['name'][0] = $this->getFileName($arrFile['name'][0], $this->strTemporaryPath);
                }

                
    $_FILES[$this->strName] = $arrFile;
                unset(
    $_FILES[$strTempName]); // Unset the temporary file
            
    }

            
    $varInput '';
            
    $maxlength null;

            
    // Override the default maxlength value
            
    if (isset($this->arrConfiguration['maxlength'])) {
                
    $maxlength $GLOBALS['TL_CONFIG']['maxFileSize'];
                
    $GLOBALS['TL_CONFIG']['maxFileSize'] = $this->getMaximumFileSize();
            }

            try {
                
    $varInput $objUploader->uploadTo($this->strTemporaryPath);

                if (
    $objUploader->hasError()) {
                    foreach (
    $_SESSION['TL_ERROR'] as $strError) {
                        
    $this->addError($strError);
                    }
                }

                \
    Message::reset();
            } catch (\
    Exception $e) {
                
    $this->addError($e->getMessage());
            }

            
    // Restore the default maxlength value
            
    if ($maxlength !== null) {
                
    $GLOBALS['TL_CONFIG']['maxFileSize'] = $maxlength;
            }

            if (!
    is_array($varInput) || empty($varInput)) {
                
    $this->addError($GLOBALS['TL_LANG']['MSC']['avatar_error']);
            }

            
    $varInput $varInput[0];
            
    $strExtension pathinfo($varInputPATHINFO_EXTENSION);
            
    $arrAllowedTypes trimsplit(','strtolower($this->getAllowedExtensions()));

            
    // File type not allowed
            
    if (!in_array(strtolower($strExtension), $arrAllowedTypes)) {
                
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['filetype'], $strExtension));
            }

            
    // Check image size
            
    if (($arrImageSize = @getimagesize(TL_ROOT '/' $varInput)) !== false) {

                
    // Image exceeds maximum image width
                
    if ($arrImageSize[0] > $GLOBALS['TL_CONFIG']['imageWidth']) {
                    
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['filewidth'], ''$GLOBALS['TL_CONFIG']['imageWidth']));
                }

                
    // Image exceeds maximum image height
                
    if ($arrImageSize[1] > $GLOBALS['TL_CONFIG']['imageHeight']) {
                    
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['fileheight'], ''$GLOBALS['TL_CONFIG']['imageHeight']));
                }

                
    // Image exceeds minimum image width
                
    if ($arrImageSize[0] < $this->arrAvatarSize[0]) {
                    
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['avatar_width'], $this->arrAvatarSize[0]));
                }

                
    // Image exceeds minimum image height
                
    if ($arrImageSize[1] < $this->arrAvatarSize[1]) {
                    
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['avatar_height'], $this->arrAvatarSize[1]));
                }
            }
            \
    System::log('Ein Log-Eintrag '.$varInput__CLASS__.'::'.__FUNCTION__TL_GENERAL);
            return 
    $varInput;
        }

        
    /**
         * Return the value
         * @param mixed
         * @return mixed
         */
        
    protected function validator($varInput)
        {
            
    // Check the mandatoriness
            
    if ($varInput == '' && $this->mandatory) {
                
    $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['mandatory'], $this->strLabel));
                return 
    '';
            }

            
    $varReturn $varInput;

            
    // Delete the file
            
    if ($varInput == '' && $this->varValue != '') {
                \
    Files::getInstance()->delete($this->varValue);
            }

            
    // Move file to the destination folder
            
    if (is_file(TL_ROOT '/' $varInput) && $this->isTemporaryFile($varInput)) {
                
    $strAvatar = \Avatar::find($this->getId(), $this->getUploadPath());

                
    // Delete the current avatar
                
    if ($strAvatar != '') {
                    \
    Files::getInstance()->delete($strAvatar);
                }

                
    $strNew $this->getUploadPath() . '/' $this->getId() . '-' md5(uniqid(''true)) . '.' pathinfo($varInputPATHINFO_EXTENSION);

                if (\
    Files::getInstance()->rename($varInput$strNew)) {
                    
    $varReturn $strNew;
                }
            }
            \
    System::log('Ein Log-Eintrag2'.$varReturn__CLASS__.'::'.__FUNCTION__TL_GENERAL);
            return 
    $varReturn;
        }

        
    /**
         * Check if file is temporary
         * @param stirng
         * @return boolean
         */
        
    protected function isTemporaryFile($strFile)
        {
            if (
    stripos($strFile$this->strThumbnailPath) !== false) {
                return 
    true;
            }

            return 
    stripos($strFile$this->strTemporaryPath) !== false;
        }

        
    /**
         * Return the thumbnail path for a file
         * @param string
         * @return string
         */
        
    protected function getThumbnailPath($strFile)
        {
            
    $strFile basename($strFile);
            
    $strFolder $this->strThumbnailPath '/' substr(md5($strFile), 01);

            
    // Make sure the folder exists
            
    new \Folder($strFolder);

            if (
    file_exists(TL_ROOT '/' $strFolder '/' $strFile)) {
                
    $strFile $this->getFileName(basename($strFile), $strFolder); // @todo - basename here?
            
    }

            return 
    $strFolder '/' $strFile;
        }

        
    /**
         * Get a thumbnail and return it as path
         * @param string
         * @return string
         */
        
    protected function getThumbnail($strFile)
        {
            if (!
    is_file(TL_ROOT '/' $strFile)) {
                return 
    '';
            }

            list(
    $intWidth$intHeight) = $this->getThumbnailDimensions($strFile);
            
    $strNew $this->getThumbnailPath($strFile);

            
    // Copy the file
            
    if (\Files::getInstance()->copy($strFile$strNew)) {
                
    $strFile $strNew;
            }

            return \
    Image::get($strFile$intWidth$intHeight'proportional');
        }

        
    /**
         * Get a thumbnail dimensions as array
         * @param string
         * @return array
         */
        
    protected function getThumbnailDimensions($strFile)
        {
            if (!
    is_file(TL_ROOT '/' $strFile)) {
                return array();
            }

            
    $intWidth $this->arrThumbSize[0];
            
    $intHeight $this->arrThumbSize[1];
            
    $arrSize = @getimagesize(TL_ROOT '/' $strFile);

            
    // Do not enlarge image
            
    if ($arrSize[0] < $intWidth && $arrSize[1] < $intHeight) {
                
    $intWidth $arrSize[0];
                
    $intHeight $arrSize[1];
            }

            return array(
    $intWidth$intHeight);
        }

        
    /**
         * Get the new file name if it already exists in the folder
         * @param string
         * @param string
         * @return string
         */
        
    protected function getFileName($strFile$strFolder)
        {
            if (!
    file_exists(TL_ROOT '/' $strFolder '/' $strFile)) {
                return 
    $strFile;
            }

            
    $offset 1;
            
    $pathinfo pathinfo($strFile);
            
    $name $pathinfo['filename'];

            
    $arrAll scan(TL_ROOT '/' $strFolder);
            
    $arrFiles preg_grep('/^' preg_quote($name'/') . '.*\.' preg_quote($pathinfo['extension'], '/') . '/'$arrAll);

            foreach (
    $arrFiles as $file) {
                if (
    preg_match('/__[0-9]+\.' preg_quote($pathinfo['extension'], '/') . '$/'$file)) {
                    
    $file str_replace('.' $pathinfo['extension'], ''$file);
                    
    $intValue intval(substr($file, (strrpos($file'_') + 1)));

                    
    $offset max($offset$intValue);
                }
            }

            return 
    str_replace($name$name '__' . ++$offset$strFile);
        }

        
    /**
         * Crop the image and return the file path
         * @param string
         * @param integer
         * @param integer
         * @return string
         */
        
    protected function cropImage($strFile$intPositionX$intPositionY$intSelectionWidth$intSelectionHeight)
        {
            
    $strThumbnail $this->getThumbnailPath($strFile);
            list(
    $intWidth$intHeight) = $this->getThumbnailDimensions($strFile);

            
    // Resize to thumbnail size first
            
    \Image::resize($strFile$intWidth$intHeight'proportional');

            
    $arrGdinfo gd_info();
            
    $strGdVersion preg_replace('/[^0-9\.]+/'''$arrGdinfo['GD Version']);
            
    $strNewImage imagecreatetruecolor($this->arrAvatarSize[0], $this->arrAvatarSize[1]);
            
    $strExtension strtolower(pathinfo($strFilePATHINFO_EXTENSION));

            switch (
    $strExtension) {
                case 
    'gif':
                    if (
    $arrGdinfo['GIF Read Support']) {
                        
    $strSourceImage imagecreatefromgif(TL_ROOT '/' $strFile);
                        
    $intTranspIndex imagecolortransparent($strSourceImage);

                        
    // Handle transparency
                        
    if ($intTranspIndex >= && $intTranspIndex imagecolorstotal($strSourceImage)) {
                            
    $arrColor imagecolorsforindex($strSourceImage$intTranspIndex);
                            
    $intTranspIndex imagecolorallocate($strNewImage$arrColor['red'], $arrColor['green'], $arrColor['blue']);
                            
    imagefill($strNewImage00$intTranspIndex);
                            
    imagecolortransparent($strNewImage$intTranspIndex);
                        }
                    }
                    break;

                case 
    'jpg':
                case 
    'jpeg':
                    if (
    $arrGdinfo['JPG Support'] || $arrGdinfo['JPEG Support']) {
                        
    $strSourceImage imagecreatefromjpeg(TL_ROOT '/' $strFile);
                    }
                    break;

                case 
    'png':
                    if (
    $arrGdinfo['PNG Support']) {
                        
    $strSourceImage imagecreatefrompng(TL_ROOT '/' $strFile);

                        
    // Handle transparency (GDlib >= 2.0 required)
                        
    if (version_compare($strGdVersion'2.0''>=')) {
                            
    imagealphablending($strNewImagefalse);
                            
    $intTranspIndex imagecolorallocatealpha($strNewImage000127);
                            
    imagefill($strNewImage00$intTranspIndex);
                            
    imagesavealpha($strNewImagetrue);
                        }
                    }
                    break;
            }

            
    // The new image could not be created
            
    if (!$strSourceImage) {
                
    imagedestroy($strNewImage);
                \
    System::log('Image "' $strFile '" could not be processed'__METHOD__TL_ERROR);
                return 
    null;
            }

            
    imagecopyresampled($strNewImage$strSourceImage00intval($intPositionX), intval($intPositionY), $this->arrAvatarSize[0], $this->arrAvatarSize[1], $intSelectionWidth$intSelectionHeight);

            
    // Create the new image
            
    switch ($strExtension) {
                case 
    'gif':
                    
    imagegif($strNewImageTL_ROOT '/' $strThumbnail);
                    break;

                case 
    'jpg':
                case 
    'jpeg':
                    
    imagejpeg($strNewImageTL_ROOT '/' $strThumbnail, (!$GLOBALS['TL_CONFIG']['jpgQuality'] ? 80 $GLOBALS['TL_CONFIG']['jpgQuality']));
                    break;

                case 
    'png':
                    
    // Optimize non-truecolor images (see #2426)
                    
    if (version_compare($strGdVersion'2.0''>=') && function_exists('imagecolormatch') && !imageistruecolor($strSourceImage)) {
                        
    // TODO: make it work with transparent images, too
                        
    if (imagecolortransparent($strSourceImage) == -1) {
                            
    $intColors imagecolorstotal($strSourceImage);

                            
    // Convert to a palette image
                            // @see http://www.php.net/manual/de/function.imagetruecolortopalette.php#44803
                            
    if ($intColors && $intColors 256) {
                                
    $wi imagesx($strNewImage);
                                
    $he imagesy($strNewImage);
                                
    $ch imagecreatetruecolor($wi$he);
                                
    imagecopymerge($ch$strNewImage0000$wi$he100);
                                
    imagetruecolortopalette($strNewImagefalse$intColors);
                                
    imagecolormatch($ch$strNewImage);
                                
    imagedestroy($ch);
                            }
                        }
                    }

                    
    imagepng($strNewImageTL_ROOT '/' $strThumbnail);
                    break;
            }

            
    // Destroy the temporary images
            
    imagedestroy($strSourceImage);
            
    imagedestroy($strNewImage);

            return 
    $strThumbnail;
        }

        
    /**
         * Get the thumbnail size
         * @return array
         */
        
    abstract protected function getThumbnailSize();

        
    /**
         * Get the avatar size
         * @return array
         */
        
    abstract protected function getAvatarSize();

        
    /**
         * Get the allowed extensions
         * @return string
         */
        
    abstract protected function getAllowedExtensions();

        
    /**
         * Get the maximum file size
         * @return string
         */
        
    abstract protected function getMaximumFileSize();

        
    /**
         * Get the upload path
         * @return string
         */
        
    abstract protected function getUploadPath();

        
    /**
         * Get the reference ID
         * @return integer
         */
        
    abstract protected function getId();


  8. #8
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Immer noch schwer für mich dateien zu finden und das richte use abzuleiten.

    /vendor/contao/core-bundle/src/Resources/contao/library/Contao
    use Contao\UploadableWidgetInterface ?

    Danke =)

  9. #9
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    hat, wenn es richtig ist, aber nichts gebracht leider

  10. #10
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Auf 4.9 gibt es kein Problem. Ist also wirklich mit 4.13 erst

  11. #11
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.040
    Partner-ID
    10107

    Standard

    Gibt es die Extension irgendwo auf Github?
    » sponsor me via GitHub or PayPal or Revolut

  12. #12
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Klar: https://github.com/terminal42/contao-avatar/tree/1.3.4
    Dort ist auch ein issue auf, leider ohne Austausch seit September.
    4.13. wird ja immer relevanter, wäre schön wenn sich eine Lösung findet.

    Danke dir soweit

  13. #13
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.040
    Partner-ID
    10107

    Standard

    Meinst du dieses Issue: https://github.com/terminal42/contao-avatar/issues/27 ?

    In diesem Issue wurde das Problem nicht genau beschrieben. Wenn du eine genaue Problembeschreibung hast, poste diese dort. Also eine Schritt für Schritt Anleitung was du machst bzw. machen willst und was passiert bzw. nicht passiert.
    » sponsor me via GitHub or PayPal or Revolut

  14. #14
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    wenn man auf speichern klickt. Ist das Bild weg, da es nie von tmp zum Zielverzeichnis kommt, da die Funktion validator nicht mehr ausgeführt wird.
    Mehr kann ich dazu nicht Beitragen, als hier schon =)

  15. #15
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.040
    Partner-ID
    10107

    Standard

    Dann poste das hier: https://github.com/terminal42/contao-avatar/issues/27

    Falls sich hier sonst nichts tut, kannst du ansonsten auch die Original-Entwickler (oder auch andere Entwickler) anheuern um das zu beheben.
    » sponsor me via GitHub or PayPal or Revolut

  16. #16
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Ich persönlich entwickle das Projekt jetzt mit 4.9
    Manchmal ist die Lösung ja einfach mit wenigen Zeilenänderungen.
    Danke für deine Bemühung hier und Allgemein!

  17. #17
    Contao-Nutzer
    Registriert seit
    09.01.2011.
    Beiträge
    234

    Standard

    Hab eine Lösung: https://github.com/terminal42/contao-avatar/issues/27

    Diese umgeht das eigentliche Problem, funktioniert aber =)

    der validator ignoriert den dca type avatar, auch die Orginal Widget Klasse überspringt diese (Contao 4.13).
    Warum und wie dies zu beheben konnte ich in vielen Stunden leider nicht erarbeiten.

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Lesezeichen

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •