Safety-related privileges; internals
This commit is contained in:
parent
bc01fd7dce
commit
bb9ab81fed
12 changed files with 99 additions and 40 deletions
|
@ -28,5 +28,12 @@ Kind regards,
|
||||||
|
|
||||||
[privileges]
|
[privileges]
|
||||||
uploadPost=registered
|
uploadPost=registered
|
||||||
|
viewPost=anonymous
|
||||||
|
viewPost.sketchy=registered
|
||||||
|
viewPost.unsafe=registered
|
||||||
listPosts=anonymous
|
listPosts=anonymous
|
||||||
|
listPosts.sketchy=registered
|
||||||
|
listPosts.unsafe=registered
|
||||||
listUsers=registered
|
listUsers=registered
|
||||||
|
listComments=registered
|
||||||
|
retrievePost=anonymous
|
||||||
|
|
|
@ -34,7 +34,8 @@ class PostController
|
||||||
$params[':limit'] = 20;
|
$params[':limit'] = 20;
|
||||||
$params[':offset'] = ($page - 1) * $params[':limit'];
|
$params[':offset'] = ($page - 1) * $params[':limit'];
|
||||||
|
|
||||||
//todo safety
|
//todo safety [user choice]
|
||||||
|
//todo safety [user privileges]
|
||||||
//todo construct WHERE based on filters
|
//todo construct WHERE based on filters
|
||||||
$whereSql = '';
|
$whereSql = '';
|
||||||
|
|
||||||
|
@ -138,8 +139,8 @@ class PostController
|
||||||
if (!$post)
|
if (!$post)
|
||||||
throw new SimpleException('Invalid post ID "' . $id . '"');
|
throw new SimpleException('Invalid post ID "' . $id . '"');
|
||||||
|
|
||||||
//todo: verify access rank...?
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost);
|
||||||
//todo: verify sketchy, nsfw, sfw
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, PostSafety::toString($post->safety));
|
||||||
|
|
||||||
$this->context->subTitle = 'showing @' . $post->id;
|
$this->context->subTitle = 'showing @' . $post->id;
|
||||||
$this->context->transport->post = $post;
|
$this->context->transport->post = $post;
|
||||||
|
@ -147,9 +148,9 @@ class PostController
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action that renders the requested file itself and sends it to user.
|
* Action that renders the requested file itself and sends it to user.
|
||||||
* @route /post/send/{name}
|
* @route /post/retrieve/{name}
|
||||||
*/
|
*/
|
||||||
public function sendAction($name)
|
public function retrieveAction($name)
|
||||||
{
|
{
|
||||||
$this->context->layoutName = 'layout-file';
|
$this->context->layoutName = 'layout-file';
|
||||||
|
|
||||||
|
@ -157,10 +158,8 @@ class PostController
|
||||||
if (!$post)
|
if (!$post)
|
||||||
throw new SimpleException('Invalid post name "' . $name . '"');
|
throw new SimpleException('Invalid post name "' . $name . '"');
|
||||||
|
|
||||||
//I guess access rank shouldn't be verified here. If someone arrives
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::RetrievePost);
|
||||||
//here, they already know the full name of the post (not just the ID)
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::RetrievePost, PostSafety::toString($post->safety));
|
||||||
//either by visiting the HTML container page or by having hotlink.
|
|
||||||
//Such users should be trusted.
|
|
||||||
|
|
||||||
$path = $this->config->main->filesPath . DIRECTORY_SEPARATOR . $post->name;
|
$path = $this->config->main->filesPath . DIRECTORY_SEPARATOR . $post->name;
|
||||||
if (!file_exists($path))
|
if (!file_exists($path))
|
||||||
|
|
10
src/Enum.php
Normal file
10
src/Enum.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
class Enum
|
||||||
|
{
|
||||||
|
public static function toString($constant)
|
||||||
|
{
|
||||||
|
$cls = new ReflectionClass(get_called_class());
|
||||||
|
$constants = $cls->getConstants();
|
||||||
|
return array_search($constant, $constants);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,26 +5,45 @@ class PrivilegesHelper
|
||||||
|
|
||||||
public static function init()
|
public static function init()
|
||||||
{
|
{
|
||||||
$privileges = \Chibi\Registry::getConfig()->privileges;
|
self::$privileges = [];
|
||||||
foreach ($privileges as $privilegeName => $minAccessRankName)
|
foreach (\Chibi\Registry::getConfig()->privileges as $key => $minAccessRankName)
|
||||||
{
|
{
|
||||||
$privilege = TextHelper::resolveConstant($privilegeName, 'Privilege');
|
if (strpos($key, '.') === false)
|
||||||
|
$key .= '.';
|
||||||
|
list ($privilegeName, $flag) = explode('.', $key);
|
||||||
|
$privilegeName = TextHelper::camelCaseToKebabCase($privilegeName);
|
||||||
|
$flag = TextHelper::camelCaseToKebabCase($flag);
|
||||||
|
$key = rtrim($privilegeName . '.' . $flag, '.');
|
||||||
|
|
||||||
$minAccessRank = TextHelper::resolveConstant($minAccessRankName, 'AccessRank');
|
$minAccessRank = TextHelper::resolveConstant($minAccessRankName, 'AccessRank');
|
||||||
self::$privileges[$privilege] = $minAccessRank;
|
self::$privileges[$key] = $minAccessRank;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function confirm($user, $privilege)
|
public static function confirm($user, $privilege, $flag = null)
|
||||||
{
|
{
|
||||||
$minAccessRank = isset(self::$privileges[$privilege])
|
$minAccessRank = AccessRank::Admin;
|
||||||
? self::$privileges[$privilege]
|
|
||||||
: AccessRank::Admin;
|
$key = TextHelper::camelCaseToKebabCase(Privilege::toString($privilege));
|
||||||
|
if (isset(self::$privileges[$key]))
|
||||||
|
{
|
||||||
|
$minAccessRank = self::$privileges[$key];
|
||||||
|
}
|
||||||
|
if ($flag != null)
|
||||||
|
{
|
||||||
|
$key2 = $key . '.' . strtolower($flag);
|
||||||
|
if (isset(self::$privileges[$key2]))
|
||||||
|
{
|
||||||
|
$minAccessRank = self::$privileges[$key2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return intval($user->access_rank) >= $minAccessRank;
|
return intval($user->access_rank) >= $minAccessRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function confirmWithException($user, $privilege)
|
public static function confirmWithException($user, $privilege, $flag = null)
|
||||||
{
|
{
|
||||||
if (!self::confirm($user, $privilege))
|
if (!self::confirm($user, $privilege, $flag))
|
||||||
{
|
{
|
||||||
throw new SimpleException('Insufficient privileges');
|
throw new SimpleException('Insufficient privileges');
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,29 @@ class TextHelper
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function kebabCaseToCamelCase($string)
|
||||||
|
{
|
||||||
|
$string = preg_split('/-/', $string);
|
||||||
|
$string = array_map('trim', $string);
|
||||||
|
$string = array_map('ucfirst', $string);
|
||||||
|
$string = join('', $string);
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function camelCaseToKebabCase($string)
|
||||||
|
{
|
||||||
|
$string = preg_replace_callback('/[A-Z]/', function($x)
|
||||||
|
{
|
||||||
|
return '-' . strtolower($x[0]);
|
||||||
|
}, $string);
|
||||||
|
$string = trim($string, '-');
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
public static function resolveConstant($constantName, $className = null)
|
public static function resolveConstant($constantName, $className = null)
|
||||||
{
|
{
|
||||||
|
$constantName = self::kebabCaseToCamelCase($constantName);
|
||||||
//convert from kebab-case to CamelCase
|
//convert from kebab-case to CamelCase
|
||||||
$constantName = preg_split('/-/', $constantName);
|
|
||||||
$constantName = array_map('trim', $constantName);
|
|
||||||
$constantName = array_map('ucfirst', $constantName);
|
|
||||||
$constantName = join('', $constantName);
|
|
||||||
if ($className !== null)
|
if ($className !== null)
|
||||||
{
|
{
|
||||||
$constantName = $className . '::' . $constantName;
|
$constantName = $className . '::' . $constantName;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
class AccessRank
|
class AccessRank extends Enum
|
||||||
{
|
{
|
||||||
const Anonymous = 0;
|
const Anonymous = 0;
|
||||||
const Registered = 1;
|
const Registered = 1;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
class PostSafety
|
class PostSafety extends Enum
|
||||||
{
|
{
|
||||||
const Safe = 1;
|
const Safe = 1;
|
||||||
const Sketchy = 2;
|
const Sketchy = 2;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
class PostType
|
class PostType extends Enum
|
||||||
{
|
{
|
||||||
const Image = 1;
|
const Image = 1;
|
||||||
const Flash = 2;
|
const Flash = 2;
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
class Privilege
|
class Privilege extends Enum
|
||||||
{
|
{
|
||||||
const UploadPost = 1;
|
const ListPosts = 1;
|
||||||
const ListPosts = 2;
|
const UploadPost = 2;
|
||||||
const ListUsers = 3;
|
const ViewPost = 3;
|
||||||
|
const RetrievePost = 4;
|
||||||
|
const ListUsers = 5;
|
||||||
|
const ListComments = 6;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,14 @@
|
||||||
$nav = [];
|
$nav = [];
|
||||||
|
|
||||||
$nav []= ['Home', \Chibi\UrlHelper::route('index', 'index')];
|
$nav []= ['Home', \Chibi\UrlHelper::route('index', 'index')];
|
||||||
|
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts))
|
||||||
$nav []= ['Browse', \Chibi\UrlHelper::route('post', 'list')];
|
$nav []= ['Browse', \Chibi\UrlHelper::route('post', 'list')];
|
||||||
|
|
||||||
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts))
|
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListComments))
|
||||||
{
|
|
||||||
$nav []= ['Comments', \Chibi\UrlHelper::route('comment', 'list')];
|
$nav []= ['Comments', \Chibi\UrlHelper::route('comment', 'list')];
|
||||||
|
|
||||||
|
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts))
|
||||||
$nav []= ['Favorites', \Chibi\UrlHelper::route('post', 'favorites')];
|
$nav []= ['Favorites', \Chibi\UrlHelper::route('post', 'favorites')];
|
||||||
}
|
|
||||||
|
|
||||||
if (PrivilegesHelper::confirm($this->context->user, Privilege::UploadPost))
|
if (PrivilegesHelper::confirm($this->context->user, Privilege::UploadPost))
|
||||||
$nav []= ['Upload', \Chibi\UrlHelper::route('post', 'upload')];
|
$nav []= ['Upload', \Chibi\UrlHelper::route('post', 'upload')];
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
<?php if (!empty($this->context->transport->errorMessage)): ?>
|
||||||
|
<p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p>
|
||||||
|
<?php else: ?>
|
||||||
<?php foreach ($this->context->transport->posts as $post): ?>
|
<?php foreach ($this->context->transport->posts as $post): ?>
|
||||||
<a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $post->id]) ?>">
|
<a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $post->id]) ?>">
|
||||||
Post <?php echo $post->id; ?>
|
Post <?php echo $post->id; ?>
|
||||||
</a>
|
</a>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
<?php endif ?>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php if (!empty($this->context->transport->errorMessage)): ?>
|
<?php if (!empty($this->context->transport->errorMessage)): ?>
|
||||||
<p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p>
|
<p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<img src="<?php echo \Chibi\UrlHelper::route('post', 'send', ['name' => $this->context->transport->post->name]) ?>" alt="<?php echo $this->context->transport->post->name ?>"/>
|
<img src="<?php echo \Chibi\UrlHelper::route('post', 'retrieve', ['name' => $this->context->transport->post->name]) ?>" alt="<?php echo $this->context->transport->post->name ?>"/>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
Loading…
Reference in a new issue