namespace Controllers;\r
\r
use Controllers\IDivineController;\r
-use DataAccess\IDownloadRepository;\r
-use DataAccess\Queries\DownloadQueryConstraints;\r
-use DateTime;\r
+use Services\IUserQuota;\r
\r
class DownloadTestController implements IDivineController\r
{\r
- private $_downloadRepository;\r
+ private $_quotaManager;\r
\r
public function __construct(\r
- IDownloadRepository $repository\r
+ IUserQuota $quotaManager\r
) {\r
- $this->_downloadRepository = $repository;\r
+ $this->_quotaManager = $quotaManager;\r
}\r
\r
public function indexAction() {\r
- $start = new DateTime('0:00 today');\r
- $end = new DateTime();\r
- \r
- $constraints = new DownloadQueryConstraints();\r
- $constraints->inDateRange($start, $end);\r
- $downloads = $this->_downloadRepository->findByUserId(4, $constraints);\r
-\r
- echo '<pre>';\r
- print_r($downloads);\r
- echo '</pre>';\r
+ $quota = (($this->_quotaManager->getCurrentUserQuotaRemaining())/1000)/1000;\r
+ echo $quota;\r
}\r
}\r
use Controllers\IDivineController;
use Services\Http\IHttpRequest;
use Services\Http\IHttpResponse;
+use Services\IUserSession;
+use Services\IUserQuota;
+use Domain\Entities\IDownloadFactory;
use DataAccess\IFileRepository;
+use DataAccess\IDownloadRepository;
class FileController implements IDivineController
{
private $_fileRepository;
private $_response;
private $_request;
+ private $_downloadRepository;
+ private $_downloadFactory;
+ private $_userSession;
+ private $_userQuota;
public function __construct(
IHttpRequest $request,
IHttpResponse $response,
- IFileRepository $repository
+ IFileRepository $repository,
+ IDownloadFactory $downloadFactory,
+ IDownloadRepository $downloadRepository,
+ IUserSession $userSession,
+ IUserQuota $userQuota
) {
$this->_request = $request;
$this->_response = $response;
$this->_fileRepository = $repository;
+ $this->_downloadRepository = $downloadRepository;
+ $this->_downloadFactory = $downloadFactory;
+ $this->_userSession = $userSession;
+ $this->_userQuota = $userQuota;
}
public function indexAction() {
exit();
}
+ public function servePackAction($hash)
+ {
+ $file = $this->_fileRepository->findByHash($hash);
+ $quotaRemaining = $this->_userQuota->getCurrentUserQuotaRemaining();
+
+ if(!$file) $this->notFound();
+ if(!$quotaRemaining) $this->notAuthorised();
+ if($quotaRemaining < $file->getSize()) $this->notEnoughQuota();
+
+ // TODO: Builder?
+ $download = $this->_downloadFactory->createInstance($this->_userSession->getCurrentUser(),
+ $file,
+ time(),
+ $this->_request->getIp());
+
+ $this->_downloadRepository->save($download);
+
+ $zip = '../files/' . $file->getPath() . '/' . $file->getHash() . '.zip';
+ //TODO: This may not work on all browser or something. We'll have to see. Also it may hog ram so...
+ $this->_response->setHeader('Content-Type', $file->getMimetype())
+ ->setHeader('Content-Length', $file->getSize())
+ ->setHeader('Content-Disposition', 'filename="' . $file->getFileName() . '";')
+ ->setHeader('Content-Transfer-Encoding', 'binary')
+ ->setBody(file_get_contents($zip))
+ ->sendResponse();
+ }
+
private function notFound()
{
$this->_response->setHeader('HTTP/1.0 404 Not Found', 'Nothing to see here')
->sendResponse();
exit();
}
+
+ private function notAuthorised()
+ {
+ $this->_response->setHeader('Content-Type', 'application/json')
+ ->setBody(json_encode(array('error' => 'You must be authenticated to download files')))
+ ->sendResponse();
+ exit();
+ }
+
+ private function notEnoughQuota()
+ {
+ $this->_response->setHeader('Content-Type', 'application/json')
+ ->setBody(json_encode(array('error' => 'You don\'t have enough quota remaining for this file.')))
+ ->sendResponse();
+ exit();
+ }
}
use DataAccess\IFileRepository;\r
use Domain\Entities\StepMania\ISimfile;\r
use Domain\Entities\IFile;\r
-use Domain\VOs\IFileMirror;\r
\r
class SimfileController implements IDivineController\r
{\r
private $_fileRepository;\r
private $_response;\r
private $_uploadManager;\r
- private $_userSession;\r
private $_zipParser;\r
private $_smoMatcher;\r
\r
$this->_simfileRepository = $simfileRepository;\r
$this->_packRepository = $packRepository;\r
$this->_fileRepository = $fileRepository;\r
- $this->_userSession = $userSession;\r
$this->_zipParser = $zipParser;\r
$this->_smoMatcher = $smoMatcher;\r
}\r
}\r
\r
$packMirrors = array();\r
+ \r
+ if($pack->getFile())\r
+ {\r
+ $packMirrors[] = array('source' => 'DivinElegy', 'uri' => 'files/pack/' . $pack->getFile()->getHash());\r
+ }\r
+ \r
if($pack->getFile()->getMirrors())\r
{\r
foreach($pack->getFile()->getMirrors() as $mirror)\r
->With_Name(new \Domain\VOs\Name($firstName, $lastName))
->With_Tags(array())
->With_FacebookId($facebookId)
+ ->With_Quota(100000000) //XXX: quota is in bytes
->build();
$this->_userRepository->save($newUser);
use Controllers\IDivineController;
use Services\Http\IHttpRequest;
use Services\Http\IHttpResponse;
+use Services\IUserQuota;
use DataAccess\IUserRepository;
+use Domain\Util;
class UserController implements IDivineController
{
private $_userRepository;
private $_response;
private $_request;
+ private $_userQuota;
public function __construct(
IHttpRequest $request,
IHttpResponse $response,
- IUserRepository $userRepository
+ IUserRepository $userRepository,
+ IUserQuota $userQuota
) {
$this->_request = $request;
$this->_response = $response;
$this->_userRepository = $userRepository;
+ $this->_userQuota = $userQuota;
}
public function indexAction() {
'name' => $user->getName()->getFullName(),
'displayName' => $user->getDisplayName(),
'tags' => $user->getTags(),
- 'country' => $user->getCountry()->getCountryName()
+ 'country' => $user->getCountry()->getCountryName(),
+ 'quota' => Util::bytesToHumanReadable($user->getQuota()),
+ 'quotaRemaining' => Util::bytesToHumanReadable($this->_userQuota->getCurrentUserQuotaRemaining())
);
$this->_response->setHeader('Content-Type', 'application/json')
public function map($entityName, IQueryBuilder $queryBuilder)\r
{\r
$queryString = $queryBuilder->buildQuery();\r
-\r
$statement = $this->_db->prepare(sprintf($queryString,\r
$this->_maps[$entityName]['table']\r
));\r
switch(get_class($mapsHelper))\r
{\r
case 'DataAccess\DataMapper\Helpers\IntMapsHelper':\r
+ if(!empty($row[$mapsHelper->getColumnName()]) && (string)(int)$row[$mapsHelper->getColumnName()] != $row[$mapsHelper->getColumnName()]) throw new Exception('Expected numeric value.');\r
+ $constructors[$constructor] = (int)$row[$mapsHelper->getColumnName()];\r
+ break;\r
case 'DataAccess\DataMapper\Helpers\VarcharMapsHelper':\r
$constructors[$constructor] = $row[$mapsHelper->getColumnName()];\r
break;\r
public function getYearsStepArtist();\r
public function getFacebookId();\r
public function setFacebookId($id);\r
+ public function getQuota();\r
}\r
public function With_Tags(array $tags);\r
public function With_FacebookId($id);\r
public function With_YearsStepArtist($years);\r
+ public function With_Quota($quota);\r
public function build();\r
}\r
private $_tags;\r
private $_yearsStepArtist;\r
private $_facebookId;\r
+ private $_quota;\r
\r
public function __construct(\r
ICountry $country,\r
$displayName,\r
IName $name,\r
array $tags,\r
- $facebookId\r
+ $facebookId,\r
+ $quota //TODO: Maybe quota should be implemented as an object?\r
) {\r
$this->_country = $country;\r
$this->_displayName = $displayName;\r
$this->_name = $name;\r
$this->_tags = $tags;\r
$this->_facebookId = $facebookId;\r
+ $this->_quota = $quota;\r
}\r
\r
public function getCountry() {\r
$this->_facebookId = $id;\r
}\r
\r
- public function getYearsStepArtist() {\r
+ public function getYearsStepArtist()\r
+ {\r
return $this->_yearsStepArtist;\r
}\r
+ \r
+ public function getQuota()\r
+ {\r
+ return $this->_quota;\r
+ }\r
}\r
private $_tags;\r
private $_facebookId;\r
private $_yearsStepArtist;\r
+ private $_quota;\r
\r
public function __construct(IUserFactory $userFactory)\r
{\r
return $this;\r
}\r
\r
+ public function With_Quota($quota)\r
+ {\r
+ $this->_quota = $quota;\r
+ }\r
+ \r
public function build() {\r
return $this->_userFactory\r
->createInstance($this->_country,\r
$this->_displayName,\r
$this->_name,\r
$this->_tags,\r
- $this->_facebookId);\r
+ $this->_facebookId,\r
+ $this->_quota);\r
}\r
}
\ No newline at end of file
$displayName,\r
IName $name,\r
array $tags,\r
- $facebookId\r
+ $facebookId,\r
+ $quota\r
);\r
}\r
\r
$displayName,\r
IName $name,\r
array $tags,\r
- $facebookId\r
+ $facebookId,\r
+ $quota\r
) {\r
return new User(\r
$country,\r
$displayName,\r
$name,\r
$tags,\r
- $facebookId\r
+ $facebookId,\r
+ $quota\r
);\r
}\r
}
\ No newline at end of file
\r
interface IUserStepByStepBuilder_With_FacebookId\r
{\r
+ public function With_Quota($quota);\r
+}\r
+\r
+interface IUserStepByStepBuilder_With_Quota\r
+{\r
public function With_YearsStepArtist($years); //not going to make this mandatory as it is kind of a joke\r
public function build();\r
}\r
\r
class UserStepByStepBuilder_With_FacebookId extends AbstractUserStepByStepBuilder implements IUserStepByStepBuilder_With_FacebookId\r
{\r
+ public function With_Quota($quota)\r
+ {\r
+ $this->_userBuilder->With_Quota($quota);\r
+ return new UserStepByStepBuilder_With_Quota($this->_userBuilder);\r
+ }\r
+}\r
+\r
+class UserStepByStepBuilder_With_Quota extends AbstractUserStepByStepBuilder implements IUserStepByStepBuilder_With_Quota\r
+{\r
public function With_YearsStepArtist($years) {\r
$this->_userBuilder->With_YearsStepArtist($years);\r
return $this;\r
}
return null;
}
+
+ public static function bytesToHumanReadable($bytes, $dec = 2)
+ {
+ if(!is_int($bytes)) throw new \Exception('Bytes must be an int.' . var_dump($bytes));
+
+ //Shamelessly stolen from stackoverflow: http://stackoverflow.com/questions/15188033/human-readable-file-size
+ $size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
+ $factor = floor((strlen($bytes) - 1) / 3);
+
+ return sprintf("%.{$dec}f", $bytes / pow(1000, $factor)) . @$size[$factor];
+ }
}
\ No newline at end of file
$this->_statusCode);
$statusCodeSent = true;
+ } else {
+ header(
+ sprintf('%s:%s', $headerName, $headerValue));
}
}
$this->sendHeaders()
->sendBody();
}
+
+ public function download($path)
+ {
+ $fp = fopen($path, "rb");
+ $this->sendHeaders();
+ @ob_clean();
+ rewind($fp);
+ fpassthru($fp);
+ }
}
public function getBody();
public function isRedirect();
public function sendResponse();
+ public function download($path);
}
\ No newline at end of file
--- /dev/null
+<?php
+
+namespace Services;
+
+interface IUserQuota
+{
+ public function getCurrentUserQuotaRemaining();
+}
\ No newline at end of file
interface IUserSession
{
public function getCurrentUser();
- public function getCurrentUserQuota();
}
--- /dev/null
+<?php
+
+namespace Services;
+
+use Services\IUserQuota;
+use Services\IUserSession;
+use DataAccess\IDownloadRepository;
+use DataAccess\Queries\DownloadQueryConstraints;
+use DateTime;
+
+class UserQuota implements IUserQuota
+{
+ private $_userSession;
+ private $_downloadRepository;
+
+ public function __construct(
+ IUserSession $userSession,
+ IDownloadRepository $downloadRepository
+ ) {
+ $this->_userSession = $userSession;
+ $this->_downloadRepository = $downloadRepository;
+ }
+
+ public function getCurrentUserQuotaRemaining()
+ {
+ $start = new DateTime('0:00 today'); // start of today
+ $end = new DateTime(); // now
+ $user = $this->_userSession->getCurrentUser();
+
+ if(!$user) return null;
+
+ // TODO: factory?
+ $constraints = new DownloadQueryConstraints();
+ $constraints->inDateRange($start, $end);
+ $downloads = $this->_downloadRepository->findByUserId($user->getId(), $constraints);
+
+ return $user->getQuota() - $this->sumDownloads($downloads);
+ }
+
+ private function sumDownloads(array $downloads)
+ {
+ $total = 0;
+
+ foreach($downloads as $download)
+ {
+ $total += $download->getFile()->getSize();
+ }
+
+ return $total;
+ }
+}
{
return $this->_currentUser;
}
-
- public function getCurrentUserQuota() {
- ;
- }
-
+
private function findToken()
{
if($this->_request->isPost())
'Domain\Entities\IFileFactory' => DI\object('Domain\Entities\FileFactory'),\r
'Domain\Entities\IFileBuilder' => DI\object('Domain\Entities\FileBuilder'),\r
'Domain\Entities\IFileStepByStepBuilder' => DI\object('Domain\Entities\FileStepByStepBuilder'),\r
+ \r
+ 'Domain\Entities\IDownloadFactory' => DI\object('Domain\Entities\DownloadFactory'),\r
\r
//services\r
'Services\Http\IHttpResponse' => DI\object('Services\Http\HttpResponse'),\r
->constructor(DI\link('router.maps')),\r
'Services\Uploads\IUploadManager' => DI\object('Services\Uploads\UploadManager'),\r
'Services\IUserSession' => DI\object('Services\UserSession'),\r
+ 'Services\IUserQuota' => DI\object('Services\UserQuota'),\r
'Services\Uploads\IFileFactory' => DI\object('Services\Uploads\FileFactory'),\r
'Services\IFacebookSessionFactory' => DI\object('Services\FacebookSessionFactory')\r
->constructor(DI\link('facebook.app')),\r
'displayName' => DataAccess\Varchar('display_name'),\r
'name' => DataAccess\VO('Name'),\r
'tags' => DataAccess\VOArray('Tag', 'getTags'), // TODO: Make VarcharArray class\r
- 'facebookId' => DataAccess\Varchar('facebook_id')\r
+ 'facebookId' => DataAccess\Varchar('facebook_id'),\r
+ 'quota' => DataAccess\Int('quota')\r
]\r
],\r
\r
'method' => ['GET'],\r
'controller' => 'File',\r
'action' => 'serveBanner'\r
+ ],\r
+ \r
+ '/files/pack/:hash' => [\r
+ 'method' => ['GET'],\r
+ 'controller' => 'File',\r
+ 'action' => 'servePack'\r
]\r
];\r