mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
Added package tags and docblock info for API documentation
Fixed whitespace git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@47726 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
b1f5068010
commit
bfc448fa7f
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AssetAdmin is the 'file store' section of the CMS.
|
* AssetAdmin is the 'file store' section of the CMS.
|
||||||
* It provides an interface for maniupating the File and Folder objects in the system.
|
* It provides an interface for maniupating the File and Folder objects in the system.
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special kind of complex table field for manipulating assets.
|
||||||
|
*/
|
||||||
class AssetTableField extends ComplexTableField {
|
class AssetTableField extends ComplexTableField {
|
||||||
|
|
||||||
protected $folder;
|
protected $folder;
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract base for bulk loaders of content into the SilverStripe database.
|
||||||
|
* Bulk loaders give SilverStripe authors the ability to do large-scale CSV uploads into their Sapphire databases.
|
||||||
|
*/
|
||||||
abstract class BulkLoader extends ViewableData {
|
abstract class BulkLoader extends ViewableData {
|
||||||
/**
|
/**
|
||||||
* Override this on subclasses to give the specific functions names
|
* Override this on subclasses to give the specific functions names
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to provide batch-update facilities to CMS users.
|
* Class to provide batch-update facilities to CMS users.
|
||||||
* The BulkLoaderAdmin class provides an interface for accessing all of the subclasses of BulkLoader,
|
* The BulkLoaderAdmin class provides an interface for accessing all of the subclasses of BulkLoader,
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special kind of form used to make the action dialogs that appear just underneath the top-right
|
* A special kind of form used to make the action dialogs that appear just underneath the top-right
|
||||||
* buttons in the CMS
|
* buttons in the CMS
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main "content" area of the CMS.
|
* The main "content" area of the CMS.
|
||||||
* This class creates a 2-frame layout - left-tree and right-form - to sit beneath the main
|
* This class creates a 2-frame layout - left-tree and right-form - to sit beneath the main
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment administration system within the CMS
|
||||||
|
*/
|
||||||
class CommentAdmin extends LeftAndMain {
|
class CommentAdmin extends LeftAndMain {
|
||||||
|
|
||||||
public function init() {
|
public function init() {
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special kind of ComplexTableField for managing comments.
|
||||||
|
*/
|
||||||
class CommentTableField extends ComplexTableField {
|
class CommentTableField extends ComplexTableField {
|
||||||
protected $template = "CommentTableField";
|
protected $template = "CommentTableField";
|
||||||
protected $mode;
|
protected $mode;
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
* A PHP diff engine
|
||||||
|
*/
|
||||||
|
|
||||||
// difflib.php
|
// difflib.php
|
||||||
//
|
//
|
||||||
// A PHP diff engine for phpwiki.
|
// A PHP diff engine for phpwiki.
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A FormField showing a list of files
|
||||||
|
*/
|
||||||
class FileList extends TableListField {
|
class FileList extends TableListField {
|
||||||
// bdc: added sort by Title as default behaviour
|
// bdc: added sort by Title as default behaviour
|
||||||
protected $folder;
|
protected $folder;
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a common interface for searching, viewing and editing DataObjects.
|
* Provides a common interface for searching, viewing and editing DataObjects.
|
||||||
* Extend the class to adjust functionality to your specific DataObjects.
|
* Extend the class to adjust functionality to your specific DataObjects.
|
||||||
|
@ -1,239 +1,243 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Controller handles all operation needed for ImageEditor to work(expect for GD operations).
|
* This Controller handles all operation needed for ImageEditor to work(expect for GD operations).
|
||||||
*
|
*/
|
||||||
*/
|
class ImageEditor extends Controller {
|
||||||
|
|
||||||
class ImageEditor extends Controller {
|
public $fileToEdit = "";
|
||||||
|
|
||||||
public $fileToEdit = "";
|
public $fileToEditOnlyName = "";
|
||||||
|
|
||||||
public $fileToEditOnlyName = "";
|
/**
|
||||||
|
* Includes all JS required for ImageEditor. This method requires setting
|
||||||
|
* a fileToEdit URL in POST.
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function index() {
|
||||||
|
Requirements::clear();
|
||||||
|
Requirements::javascript('jsparty/prototype.js');
|
||||||
|
Requirements::javascript('jsparty/scriptaculous/scriptaculous.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Utils.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/ImageHistory.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Image.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/ImageTransformation.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Resizeable.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Effects.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Environment.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Crop.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/Resize.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/ImageBox.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/ImageEditor.js');
|
||||||
|
Requirements::javascript('cms/javascript/ImageEditor/DocumentBody.js');
|
||||||
|
|
||||||
/**
|
Requirements::javascript('jsparty/loader.js');
|
||||||
* Includes all JS required for ImageEditor. This method requires setting
|
Requirements::javascript('jsparty/behaviour.js');
|
||||||
* a fileToEdit URL in POST.
|
Requirements::javascript('cms/javascript/LeftAndMain.js');
|
||||||
*
|
Requirements::css('cms/css/ImageEditor/ImageEditor.css');
|
||||||
* @return String
|
|
||||||
*/
|
|
||||||
public function index() {
|
|
||||||
Requirements::clear();
|
|
||||||
Requirements::javascript('jsparty/prototype.js');
|
|
||||||
Requirements::javascript('jsparty/scriptaculous/scriptaculous.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Utils.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/ImageHistory.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Image.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/ImageTransformation.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Resizeable.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Effects.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Environment.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Crop.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/Resize.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/ImageBox.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/ImageEditor.js');
|
|
||||||
Requirements::javascript('cms/javascript/ImageEditor/DocumentBody.js');
|
|
||||||
|
|
||||||
Requirements::javascript('jsparty/loader.js');
|
if(!isset($this->requestParams['fileToEdit'])) $this->raiseError();
|
||||||
Requirements::javascript('jsparty/behaviour.js');
|
$fileWithPath = $this->requestParams['fileToEdit'];
|
||||||
Requirements::javascript('cms/javascript/LeftAndMain.js');
|
$this->fileToEdit = $this->file2Origin($fileWithPath);
|
||||||
Requirements::css('cms/css/ImageEditor/ImageEditor.css');
|
$this->fileToEditOnlyName = $this->urlToFilename($this->fileToEdit);
|
||||||
|
return $this->renderWith(__CLASS__);
|
||||||
|
}
|
||||||
|
|
||||||
if(!isset($this->requestParams['fileToEdit'])) $this->raiseError();
|
/**
|
||||||
$fileWithPath = $this->requestParams['fileToEdit'];
|
* Method is used for manipulating photos.
|
||||||
$this->fileToEdit = $this->file2Origin($fileWithPath);
|
* Method requires two params set in POST
|
||||||
$this->fileToEditOnlyName = $this->urlToFilename($this->fileToEdit);
|
* file - file on which operation will be performed
|
||||||
return $this->renderWith(__CLASS__);
|
* command - name of operation(crop|rotate|resize)
|
||||||
|
*
|
||||||
|
* Each operation requires additional parameters.
|
||||||
|
*
|
||||||
|
* @return String - JSON array with image properties (width,height,url).
|
||||||
|
*/
|
||||||
|
public function manipulate() {
|
||||||
|
$fileName = $this->requestParams['file'];
|
||||||
|
if(strpos($fileName,'?') !== false) $fileName = substr($fileName,0,strpos($fileName,'?'));
|
||||||
|
$command = $this->requestParams['command'];
|
||||||
|
$this->checkFileExists($fileName);
|
||||||
|
$fileInfo = pathinfo($fileName);
|
||||||
|
$gd = new GD($this->url2File($fileName));
|
||||||
|
switch($command) {
|
||||||
|
case 'rotate':
|
||||||
|
$angle = $_POST['angle'];
|
||||||
|
$gd = $gd->rotate($angle);
|
||||||
|
break;
|
||||||
|
case 'resize':
|
||||||
|
$imageNewWidth = $_POST['newImageWidth'];
|
||||||
|
$imageNewHeight = $_POST['newImageHeight'];
|
||||||
|
$gd = $gd->resize($imageNewWidth,$imageNewHeight);
|
||||||
|
break;
|
||||||
|
case 'crop':
|
||||||
|
$top = $_POST['top'];
|
||||||
|
$left = $_POST['left'];
|
||||||
|
$width = $_POST['width'];
|
||||||
|
$height = $_POST['height'];
|
||||||
|
$gd = $gd->crop($top,$left,$width,$height);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
$rand = md5(rand(1,100000));
|
||||||
|
$gd->writeTo('../assets/_tmp/' . $rand . '.' . $fileInfo['extension']);
|
||||||
|
return $this->getImageInfoInJSON($gd,'assets/_tmp/' . $rand . '.' . $fileInfo['extension']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method is used for manipulating photos.
|
* Method is used for saving photos.
|
||||||
* Method requires two params set in POST
|
* Method requires two params set in POST
|
||||||
* file - file on which operation will be performed
|
* originalFile - this file will be replaced by second file
|
||||||
* command - name of operation(crop|rotate|resize)
|
* editedFile - this file will replace first file.
|
||||||
*
|
*
|
||||||
* Each operation requires additional parameters.
|
* After replacing original file all thumbnails created from it are removed.
|
||||||
*
|
*
|
||||||
* @return String - JSON array with image properties (width,height,url).
|
* @return String - Message that everything went ok.
|
||||||
*/
|
*/
|
||||||
public function manipulate() {
|
|
||||||
$fileName = $this->requestParams['file'];
|
|
||||||
if(strpos($fileName,'?') !== false) $fileName = substr($fileName,0,strpos($fileName,'?'));
|
|
||||||
$command = $this->requestParams['command'];
|
|
||||||
$this->checkFileExists($fileName);
|
|
||||||
$fileInfo = pathinfo($fileName);
|
|
||||||
$gd = new GD($this->url2File($fileName));
|
|
||||||
switch($command) {
|
|
||||||
case 'rotate':
|
|
||||||
$angle = $_POST['angle'];
|
|
||||||
$gd = $gd->rotate($angle);
|
|
||||||
break;
|
|
||||||
case 'resize':
|
|
||||||
$imageNewWidth = $_POST['newImageWidth'];
|
|
||||||
$imageNewHeight = $_POST['newImageHeight'];
|
|
||||||
$gd = $gd->resize($imageNewWidth,$imageNewHeight);
|
|
||||||
break;
|
|
||||||
case 'crop':
|
|
||||||
$top = $_POST['top'];
|
|
||||||
$left = $_POST['left'];
|
|
||||||
$width = $_POST['width'];
|
|
||||||
$height = $_POST['height'];
|
|
||||||
$gd = $gd->crop($top,$left,$width,$height);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$rand = md5(rand(1,100000));
|
|
||||||
$gd->writeTo('../assets/_tmp/' . $rand . '.' . $fileInfo['extension']);
|
|
||||||
return $this->getImageInfoInJSON($gd,'assets/_tmp/' . $rand . '.' . $fileInfo['extension']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public function save() {
|
||||||
* Method is used for saving photos.
|
if(isset($this->requestParams['originalFile']) && isset($this->requestParams['editedFile'])) {
|
||||||
* Method requires two params set in POST
|
$originalFile = $this->requestParams['originalFile'];
|
||||||
* originalFile - this file will be replaced by second file
|
$editedFile = $this->requestParams['editedFile'];
|
||||||
* editedFile - this file will replace first file.
|
if(strpos($originalFile,'?') !== false) $originalFile = substr($originalFile,0,strpos($originalFile,'?'));
|
||||||
*
|
if($this->checkFileExists($originalFile) && $this->checkFileExists($editedFile)) {
|
||||||
* After replacing original file all thumbnails created from it are removed.
|
if($editedFile != $originalFile && copy($this->url2File($editedFile),$this->url2File($originalFile))) {
|
||||||
*
|
$image = DataObject::get_one('File','Filename = \'' . substr($this->url2File($originalFile),3) . '\'');
|
||||||
* @return String - Message that everything went ok.
|
$image->deleteFormattedImages();
|
||||||
*/
|
$image->generateFormattedImage('AssetLibraryPreview');
|
||||||
|
|
||||||
public function save() {
|
|
||||||
if(isset($this->requestParams['originalFile']) && isset($this->requestParams['editedFile'])) {
|
|
||||||
$originalFile = $this->requestParams['originalFile'];
|
|
||||||
$editedFile = $this->requestParams['editedFile'];
|
|
||||||
if(strpos($originalFile,'?') !== false) $originalFile = substr($originalFile,0,strpos($originalFile,'?'));
|
|
||||||
if($this->checkFileExists($originalFile) && $this->checkFileExists($editedFile)) {
|
|
||||||
if($editedFile != $originalFile && copy($this->url2File($editedFile),$this->url2File($originalFile))) {
|
|
||||||
$image = DataObject::get_one('File','Filename = \'' . substr($this->url2File($originalFile),3) . '\'');
|
|
||||||
$image->deleteFormattedImages();
|
|
||||||
$image->generateFormattedImage('AssetLibraryPreview');
|
|
||||||
} else {
|
|
||||||
$this->raiseError();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$this->raiseError();
|
$this->raiseError();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->raiseError();
|
$this->raiseError();
|
||||||
}
|
}
|
||||||
return 'parent.parent.parent.statusMessage(\'Image saved\',\'good\',false);';
|
} else {
|
||||||
|
$this->raiseError();
|
||||||
}
|
}
|
||||||
|
return 'parent.parent.parent.statusMessage(\'Image saved\',\'good\',false);';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method is invoked when ImageEditor is closed whether image is saved or not.
|
* Method is invoked when ImageEditor is closed whether image is saved or not.
|
||||||
*
|
*
|
||||||
* /assets/tmp is folder where we store temporary images created during editing so
|
* /assets/tmp is folder where we store temporary images created during editing so
|
||||||
* after closing they are no necessity to keep them.
|
* after closing they are no necessity to keep them.
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function close() {
|
public function close() {
|
||||||
$tmpDir = '../assets/_tmp';
|
$tmpDir = '../assets/_tmp';
|
||||||
if(file_exists($tmpDir)) {
|
if(file_exists($tmpDir)) {
|
||||||
Filesystem::removeFolder($tmpDir);
|
Filesystem::removeFolder($tmpDir);
|
||||||
mkdir($tmpDir, Filesystem::$folder_create_mask);
|
mkdir($tmpDir, Filesystem::$folder_create_mask);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method return JSON array containing info about image.
|
|
||||||
*
|
|
||||||
* @param gd - GD object used for retrieving info about image
|
|
||||||
* @param file
|
|
||||||
*
|
|
||||||
* @return string JSON array explained in manipulate method comment
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function getImageInfoInJSON(GD $gd,$file) {
|
|
||||||
return '{"fileName":"' . $file . '","width":' . $gd->getWidth() . ',"height":' . $gd->getHeight() . '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method converts thumbnail file name to file name of it's "parent"
|
|
||||||
*
|
|
||||||
* @param file - name of thumbnail file
|
|
||||||
*
|
|
||||||
* @return string name of parent file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function file2Origin($file) {
|
|
||||||
$file = str_replace('_resampled/','',$file);
|
|
||||||
$file = str_replace('_resampled/','',$file);
|
|
||||||
$file = str_replace('AssetLibraryPreview-','',$file);
|
|
||||||
$this->checkFileExists($file);
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Method converts URL of file to file path in file system.
|
|
||||||
*
|
|
||||||
* @param url - url of file
|
|
||||||
*
|
|
||||||
* @return string path of file in file system
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function url2File($url) {
|
|
||||||
return '..' . substr($url,strpos($url,'/assets'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method checks if file exists and have proper name and extension.
|
|
||||||
*
|
|
||||||
* If any of constraints aren't fulfilled method will generate error.
|
|
||||||
*
|
|
||||||
* @param url - url of file
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function checkFileExists($url) {
|
|
||||||
if(strpos($url,'?') !== false) $url = substr($url,0,strpos($url,'?'));
|
|
||||||
$pathInfo = pathinfo($url);
|
|
||||||
if(count($pathInfo) < 3) $this->raiseError();
|
|
||||||
if(!in_array($pathInfo['extension'],array('jpeg','jpg','jpe','png','gif','JPEG','JPG','JPE','PNG','GIF'))) $this->raiseError();
|
|
||||||
$path = explode('/',$pathInfo['dirname']);
|
|
||||||
if(count($path) > 1) {
|
|
||||||
$assetId = array_search('assets',$path);
|
|
||||||
if($assetId > 0) {
|
|
||||||
$realPath = '../' . implode('/',array_slice($path,$assetId,count($path) - $assetId));
|
|
||||||
if(strpos($pathInfo['basename'],'AssetLibraryPreview') !== false) {
|
|
||||||
$realPath .= '/' . substr($pathInfo['basename'],strpos($pathInfo['basename'],'-'));
|
|
||||||
} else {
|
|
||||||
$realPath .= '/' . $pathInfo['basename'];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->raiseError();
|
|
||||||
}
|
|
||||||
if(file_exists($realPath)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
$this->raiseError();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->raiseError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method raiser error. Error is showed using statusMessage function.
|
|
||||||
*
|
|
||||||
* @param message - error message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function raiseError($message = "") {
|
|
||||||
echo "parent.parent.parent.statusMessage('Error: " . $message . "','bad',false);";
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method converts retrieves filename from url
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function urlToFilename($url) {
|
|
||||||
$path = pathinfo($url);
|
|
||||||
return $path['filename'] . "." . substr($path['extension'],0,strpos($path['extension'],'?'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method return JSON array containing info about image.
|
||||||
|
*
|
||||||
|
* @param gd - GD object used for retrieving info about image
|
||||||
|
* @param file
|
||||||
|
*
|
||||||
|
* @return string JSON array explained in manipulate method comment
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function getImageInfoInJSON(GD $gd,$file) {
|
||||||
|
return '{"fileName":"' . $file . '","width":' . $gd->getWidth() . ',"height":' . $gd->getHeight() . '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method converts thumbnail file name to file name of it's "parent"
|
||||||
|
*
|
||||||
|
* @param file - name of thumbnail file
|
||||||
|
*
|
||||||
|
* @return string name of parent file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function file2Origin($file) {
|
||||||
|
$file = str_replace('_resampled/','',$file);
|
||||||
|
$file = str_replace('_resampled/','',$file);
|
||||||
|
$file = str_replace('AssetLibraryPreview-','',$file);
|
||||||
|
$this->checkFileExists($file);
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Method converts URL of file to file path in file system.
|
||||||
|
*
|
||||||
|
* @param url - url of file
|
||||||
|
*
|
||||||
|
* @return string path of file in file system
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function url2File($url) {
|
||||||
|
return '..' . substr($url,strpos($url,'/assets'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method checks if file exists and have proper name and extension.
|
||||||
|
*
|
||||||
|
* If any of constraints aren't fulfilled method will generate error.
|
||||||
|
*
|
||||||
|
* @param url - url of file
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function checkFileExists($url) {
|
||||||
|
if(strpos($url,'?') !== false) $url = substr($url,0,strpos($url,'?'));
|
||||||
|
$pathInfo = pathinfo($url);
|
||||||
|
if(count($pathInfo) < 3) $this->raiseError();
|
||||||
|
if(!in_array($pathInfo['extension'],array('jpeg','jpg','jpe','png','gif','JPEG','JPG','JPE','PNG','GIF'))) $this->raiseError();
|
||||||
|
$path = explode('/',$pathInfo['dirname']);
|
||||||
|
if(count($path) > 1) {
|
||||||
|
$assetId = array_search('assets',$path);
|
||||||
|
if($assetId > 0) {
|
||||||
|
$realPath = '../' . implode('/',array_slice($path,$assetId,count($path) - $assetId));
|
||||||
|
if(strpos($pathInfo['basename'],'AssetLibraryPreview') !== false) {
|
||||||
|
$realPath .= '/' . substr($pathInfo['basename'],strpos($pathInfo['basename'],'-'));
|
||||||
|
} else {
|
||||||
|
$realPath .= '/' . $pathInfo['basename'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->raiseError();
|
||||||
|
}
|
||||||
|
if(file_exists($realPath)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->raiseError();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->raiseError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method raiser error. Error is showed using statusMessage function.
|
||||||
|
*
|
||||||
|
* @param message - error message
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function raiseError($message = "") {
|
||||||
|
echo "parent.parent.parent.statusMessage('Error: " . $message . "','bad',false);";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method converts retrieves filename from url
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function urlToFilename($url) {
|
||||||
|
$path = pathinfo($url);
|
||||||
|
return $path['filename'] . "." . substr($path['extension'],0,strpos($path['extension'],'?'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module to provide imprint statistics integration.
|
||||||
|
*/
|
||||||
class ImprintStats extends ViewableData {
|
class ImprintStats extends ViewableData {
|
||||||
protected static $imprintID;
|
protected static $imprintID;
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeftAndMain is the parent class of all the two-pane views in the CMS.
|
* LeftAndMain is the parent class of all the two-pane views in the CMS.
|
||||||
* If you are wanting to add more areas to the CMS, you can do it by subclassing LeftAndMain.
|
* If you are wanting to add more areas to the CMS, you can do it by subclassing LeftAndMain.
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form field showing a list of members.
|
||||||
|
*/
|
||||||
class MemberList extends FormField {
|
class MemberList extends FormField {
|
||||||
protected $members;
|
protected $members;
|
||||||
protected $hidePassword;
|
protected $hidePassword;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enhances {ComplexTableField} with the ability to list groups and given members.
|
* Enhances {ComplexTableField} with the ability to list groups and given members.
|
||||||
* It is based around groups, so it deletes Members from a Group rather than from the entire system.
|
* It is based around groups, so it deletes Members from a Group rather than from the entire system.
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a process in session which is incremented to calls from the client
|
* Create a process in session which is incremented to calls from the client
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form field showing a list of bounced addresses
|
||||||
|
*/
|
||||||
class BouncedList extends FormField {
|
class BouncedList extends FormField {
|
||||||
|
|
||||||
protected $nlType;
|
protected $nlType;
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single newsletter instance. Each Newsletter belongs to a NewsletterType.
|
||||||
|
*/
|
||||||
class Newsletter extends DataObject {
|
class Newsletter extends DataObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch process for sending newsletters.
|
||||||
|
*/
|
||||||
class NewsletterEmailProcess extends BatchProcess {
|
class NewsletterEmailProcess extends BatchProcess {
|
||||||
|
|
||||||
protected $subject;
|
protected $subject;
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple form field shown when the NewsletterAdmin first loads.
|
||||||
|
*/
|
||||||
class NewsletterList extends FormField {
|
class NewsletterList extends FormField {
|
||||||
function __construct($name, $mailtype, $status = "Draft") {
|
function __construct($name, $mailtype, $status = "Draft") {
|
||||||
if(is_object($mailtype)) $this->mailType = $mailtype;
|
if(is_object($mailtype)) $this->mailType = $mailtype;
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a type of newsletter, for example the weekly products update.
|
||||||
|
* The NewsletterType is associated with a recipient list and a bunch of Newsletter objects, which are each either Sent or Draft.
|
||||||
|
*/
|
||||||
class NewsletterType extends DataObject {
|
class NewsletterType extends DataObject {
|
||||||
|
|
||||||
static $db = array(
|
static $db = array(
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a file upload field.
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a field for importing recipients.
|
||||||
*/
|
*/
|
||||||
class RecipientImportField extends FormField {
|
class RecipientImportField extends FormField {
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page type for creating a page that contains a form that visitors can use to subscript to a newsletter.
|
||||||
|
*/
|
||||||
class SubscribeForm extends UserDefinedForm {
|
class SubscribeForm extends UserDefinedForm {
|
||||||
static $add_action = "a newsletter subscription form";
|
static $add_action = "a newsletter subscription form";
|
||||||
|
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should extend DropdownField
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass of DropdownField for showing a list of the newsletter templates available.
|
||||||
*/
|
*/
|
||||||
class TemplateList extends DropdownField {
|
class TemplateList extends DropdownField {
|
||||||
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a form that a user can use to unsubscribe from a mailing list
|
* @package cms
|
||||||
*/
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a form that a user can use to unsubscribe from a mailing list
|
||||||
|
*/
|
||||||
class Unsubscribe_Controller extends Page_Controller {
|
class Unsubscribe_Controller extends Page_Controller {
|
||||||
function __construct($data = null) {
|
function __construct($data = null) {
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a list of all members that have unsubscribed from the list
|
* @package cms
|
||||||
*/
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of all members that have unsubscribed from the list
|
||||||
|
*/
|
||||||
class UnsubscribedList extends FormField {
|
class UnsubscribedList extends FormField {
|
||||||
|
|
||||||
protected $nlType;
|
protected $nlType;
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage newsletter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Newsletter administration section
|
||||||
|
*/
|
||||||
class NewsletterAdmin extends LeftAndMain {
|
class NewsletterAdmin extends LeftAndMain {
|
||||||
static $subitem_class = "Member";
|
static $subitem_class = "Member";
|
||||||
|
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage pagetypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page type that lets users build a contact form.
|
||||||
|
*/
|
||||||
class UserDefinedForm extends Page {
|
class UserDefinedForm extends Page {
|
||||||
static $add_action = "a contact form";
|
static $add_action = "a contact form";
|
||||||
|
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports section of the CMS
|
||||||
|
*/
|
||||||
class ReportAdmin extends LeftAndMain {
|
class ReportAdmin extends LeftAndMain {
|
||||||
static $subitem_class = "GrantObject";
|
static $subitem_class = "GrantObject";
|
||||||
|
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security section of the CMS
|
||||||
|
*/
|
||||||
class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
||||||
static $tree_class = "Group";
|
static $tree_class = "Group";
|
||||||
static $subitem_class = "Member";
|
static $subitem_class = "Member";
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for the small reports that appear in the left hand site of the Site Content section of the CMS.
|
||||||
|
* Create subclasses of this class to build new reports.
|
||||||
|
*/
|
||||||
abstract class SideReport extends Object {
|
abstract class SideReport extends Object {
|
||||||
abstract function records();
|
abstract function records();
|
||||||
abstract function fieldsToShow();
|
abstract function fieldsToShow();
|
||||||
@ -34,6 +43,9 @@ abstract class SideReport extends Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content side-report listing empty pages
|
||||||
|
*/
|
||||||
class SideReport_EmptyPages extends SideReport {
|
class SideReport_EmptyPages extends SideReport {
|
||||||
function title() {
|
function title() {
|
||||||
return _t('SideReport.EMPTYPAGES',"Empty pages");
|
return _t('SideReport.EMPTYPAGES',"Empty pages");
|
||||||
@ -48,6 +60,9 @@ class SideReport_EmptyPages extends SideReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content side-report listing recently editing pages.
|
||||||
|
*/
|
||||||
class SideReport_RecentlyEdited extends SideReport {
|
class SideReport_RecentlyEdited extends SideReport {
|
||||||
function title() {
|
function title() {
|
||||||
return _t('SideReport.LAST2WEEKS',"Pages edited in the last 2 weeks");
|
return _t('SideReport.LAST2WEEKS',"Pages edited in the last 2 weeks");
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class lets you export a static copy of your site.
|
* This class lets you export a static copy of your site.
|
||||||
* It creates a huge number of folders each containing an index.html file.
|
* It creates a huge number of folders each containing an index.html file.
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statistics section of the CMS
|
||||||
|
*/
|
||||||
class StatisticsAdmin extends LeftAndMain {
|
class StatisticsAdmin extends LeftAndMain {
|
||||||
static $tree_class = "SiteTree";
|
static $tree_class = "SiteTree";
|
||||||
static $subitem_class = "Member";
|
static $subitem_class = "Member";
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a strip of thumbnails showing all of the images in the system.
|
* Provides a strip of thumbnails showing all of the images in the system.
|
||||||
* It will be tied to a 'parent field' that will provide it with a filter by which to reduce the number
|
* It will be tied to a 'parent field' that will provide it with a filter by which to reduce the number
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special field type for selecting and configuring widgets on a page.
|
||||||
|
*/
|
||||||
class WidgetAreaEditor extends FormField {
|
class WidgetAreaEditor extends FormField {
|
||||||
function FieldHolder() {
|
function FieldHolder() {
|
||||||
return $this->renderWith("WidgetAreaEditor");
|
return $this->renderWith("WidgetAreaEditor");
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
*
|
*
|
||||||
* See the Akismet class documentation page linked to below for usage information.
|
* See the Akismet class documentation page linked to below for usage information.
|
||||||
*
|
*
|
||||||
* @package Akismet
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
* @author Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
|
* @author Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
* @copyright Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
|
* @copyright Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
|
||||||
@ -43,8 +44,6 @@
|
|||||||
* // store the comment normally
|
* // store the comment normally
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @package akismet
|
|
||||||
* @name Akismet
|
|
||||||
* @version 0.2
|
* @version 0.2
|
||||||
* @author Alex Potsides
|
* @author Alex Potsides
|
||||||
* @link http://www.achingbrain.net/
|
* @link http://www.achingbrain.net/
|
||||||
@ -298,7 +297,6 @@ class Akismet
|
|||||||
*
|
*
|
||||||
* N.B. It is not necessary to call this class directly to use the Akismet class. This is included here mainly out of a sense of completeness.
|
* N.B. It is not necessary to call this class directly to use the Akismet class. This is included here mainly out of a sense of completeness.
|
||||||
*
|
*
|
||||||
* @package akismet
|
|
||||||
* @name SocketWriteRead
|
* @name SocketWriteRead
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
* @author Alex Potsides
|
* @author Alex Potsides
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tools for adding an optional protection question to a form.
|
* Tools for adding an optional protection question to a form.
|
||||||
* Remember to add MathSpamProtection::enabled(true); to _config.php for this question to be added to the comments form.
|
* Remember to add MathSpamProtection::enabled(true); to _config.php for this question to be added to the comments form.
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single comment on a page
|
||||||
|
*/
|
||||||
class PageComment extends DataObject {
|
class PageComment extends DataObject {
|
||||||
static $db = array(
|
static $db = array(
|
||||||
"Name" => "Varchar",
|
"Name" => "Varchar",
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an interface for viewing and adding page comments
|
* Represents an interface for viewing and adding page comments
|
||||||
* Create one, passing the page discussed to the constructor. It can then be
|
* Create one, passing the page discussed to the constructor. It can then be
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package cms
|
||||||
|
* @subpackage
|
||||||
|
*/
|
||||||
|
|
||||||
class SSAkismet extends Akismet {
|
class SSAkismet extends Akismet {
|
||||||
private static $apiKey;
|
private static $apiKey;
|
||||||
private static $saveSpam = true;
|
private static $saveSpam = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user