...
 
Commits (17)
<?php
namespace Minds\Common;
use ReflectionClass;
abstract class ChannelMode
{
const OPEN = 0;
const MODERATED = 1;
const CLOSED = 2;
final public static function toArray() : array
{
return (new ReflectionClass(static::class))->getConstants();
}
final public static function isValid($value) : bool
{
return in_array($value, static::toArray(), true);
}
}
<?php
namespace Minds\Controllers\Cli;
use Minds\Cli;
use Minds\Core\Events\Dispatcher;
use Minds\Interfaces;
class Notification extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function help($command = null)
{
switch ($command) {
case 'send':
$this->out('Send a notification');
$this->out('--namespace=<type> Notification namespace');
$this->out('--to=<user guid> User to send notification to');
$this->out('--from=<entity guid> Entity notification is from (defaults to system user)');
$this->out('--view=<view> Notification view');
$this->out('--params=<params> JSON payload data');
// no break
default:
$this->out('Syntax usage: cli notification <cmd>');
$this->displayCommandHelp();
}
}
public function exec()
{
$this->help();
}
public function send()
{
$namespace = $this->getOpt('namespace');
$to = $this->getOpt('to');
$from = $this->getOpt('from') ?? \Minds\Core\Notification\Notification::SYSTEM_ENTITY;
$view = $this->getOpt('view');
$params = $this->getOpt('params') ?? '{}';
if (is_null($namespace)) {
$this->out('namespace must be set');
return;
}
if (is_null($to)) {
$this->out('to must be set');
return;
}
if (is_null($view)) {
$this->out('view must be set');
return;
}
$paramsDecoded = json_decode($params, true);
if (is_null($paramsDecoded)) {
$this->out('Params is not valid JSON');
return;
}
$eventParams = [
'to' => [$to],
'from' => $from,
'notification_view' => $view,
'params' => $paramsDecoded
];
$sent = Dispatcher::trigger('notification', $namespace, $eventParams);
if ($sent) {
$this->out('Notification sent');
} else {
$this->out('Error sending notification - is from guid valid?');
}
}
}
......@@ -31,7 +31,7 @@ class reports implements Interfaces\Api, Interfaces\ApiAdminPam
/** @var Core\Reports\Repository $repository */
$repository = Di::_()->get('Reports\Repository');
$reports = $repository->getAll([
$reports = $repository->getList([
'state' => $state,
'limit' => $limit,
'offset' => $offset
......
......@@ -12,6 +12,7 @@ use Minds\Helpers;
use Minds\Interfaces;
use Minds\Entities;
use Minds\Api\Factory;
use Minds\Common\ChannelMode;
use ElggFile;
class channel implements Interfaces\Api
......@@ -242,6 +243,10 @@ class channel implements Interfaces\Api
}
}
if (isset($_POST['mode']) && ChannelMode::isValid($_POST['mode'])) {
$update['mode'] = $_POST['mode'];
}
if (isset($_POST['social_profiles']) && is_array($_POST['social_profiles'])) {
$profiles = [];
......
......@@ -57,6 +57,9 @@ class container implements Interfaces\Api
case 'blogs':
$type = 'object:blog';
break;
case 'all':
$type = 'all';
break;
}
//
......
<?php
/**
*
*/
namespace Minds\Controllers\api\v2\payments\stripe;
use Minds\Api\Factory;
use Minds\Common\Cookie;
use Minds\Core\Di\Di;
use Minds\Core\Config;
use Minds\Core\Session;
use Minds\Interfaces;
use Minds\Core\Payments\Stripe;
class transactions implements Interfaces\Api
{
public function get($pages)
{
$user = Session::getLoggedInUser();
$connectManager = new Stripe\Connect\Manager();
try {
$account = $connectManager->getByUser($user);
} catch (\Exception $e) {
return Factory::response([
'status' => 'error',
'message' => 'There was an error returning the usd account',
]);
}
$transactionsManger = new Stripe\Transactions\Manager();
$transactions = $transactionsManger->getByAccount($account);
return Factory::response([
'transactions' => Factory::exportable($transactions),
]);
}
public function post($pages)
{
return Factory::response([]);
}
public function put($pages)
{
return Factory::response([]);
}
public function delete($pages)
{
return Factory::response([]);
}
}
......@@ -8,6 +8,7 @@ use Minds\Interfaces;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\Session;
use Minds\Core\Permissions\Permissions;
use Minds\Core\Permissions\Entities\EntityPermissions;
class comments implements Interfaces\Api
{
......@@ -45,6 +46,13 @@ class comments implements Interfaces\Api
$entitiesBuilder = Di::_()->get('EntitiesBuilder');
$entity = $entitiesBuilder->single($pages[0]);
if (!$entity) {
return Factory::response([
'status' => 'error',
'message' => 'entity not found',
]);
}
if (!$entity->canEdit($owner)) {
return Factory::response([
'status' => 'error',
......@@ -53,8 +61,8 @@ class comments implements Interfaces\Api
}
/** @var PermissionsManager */
$manager = Di::_()->get('Permissions\Manager');
$permissions = new Permissions();
$manager = Di::_()->get('Permissions\Entities\Manager');
$permissions = new EntityPermissions();
$permissions->setAllowComments($allowed);
$manager->save($entity, $permissions);
......
<?php
namespace Minds\Controllers\api\v2\permissions;
use Minds\Api\Factory;
use Minds\Interfaces;
use Minds\Core\Di\Di;
class roles implements Interfaces\Api
{
public function get($pages)
{
Factory::isLoggedIn();
if (!isset($pages[0])) {
return Factory::response([
'status' => 'error',
'message' => 'User guid must be provided',
]);
}
try {
/** @var Core\Permissions\Manager $manager */
$manager = Di::_()->get('Permissions\Manager');
$opts = [
'user_guid' => $pages[0],
'guids' => $_GET['guids'],
];
$permissions = $manager->getList($opts);
return Factory::response([
'status' => 'success',
'roles' => $permissions,
]);
} catch (Exception $ex) {
return Factory::response([
'status' => 'error',
'message' => $ex->getMessage(),
]);
}
return Factory::response([]);
}
public function post($pages)
{
// TODO: Implement put() method.
}
public function put($pages)
{
// TODO: Implement put() method.
}
public function delete($pages)
{
// TODO: Implement put() method.
}
}
......@@ -175,7 +175,7 @@ class Manager
//filter to get todays offchain transactions
$offlineToday = array_filter($offchain->toArray(), function ($result) {
return $result->getCreatedTimestamp() > time() - (60 * 60 * 24);
return $result->getCreatedTimestamp() > (time() - (60 * 60 * 24)) * 1000;
});
//reduce the impressions to count the days boosts.
......
......@@ -95,6 +95,7 @@ class Manager
'filter_hashtags' => false,
'pinned_guids' => null,
'as_activities' => false,
'exclude' => null,
], $opts);
if (isset($opts['query']) && $opts['query']) {
......
......@@ -53,6 +53,7 @@ class Repository
'exclude_moderated' => false,
'moderation_reservations' => null,
'pinned_guids' => null,
'exclude' => null,
], $opts);
if (!$opts['type']) {
......@@ -67,6 +68,8 @@ class Repository
throw new \Exception('Unsupported period');
}
$type = $opts['type'];
$body = [
'_source' => array_unique([
'guid',
......@@ -75,7 +78,7 @@ class Repository
'time_created',
'access_id',
'moderator_guid',
$this->getSourceField($opts['type']),
$this->getSourceField($type),
]),
'query' => [
'function_score' => [
......@@ -98,7 +101,7 @@ class Repository
'sort' => [],
];
/*if ($opts['type'] === 'group' && false) {
/*if ($type === 'group' && false) {
if (!isset($body['query']['function_score']['query']['bool']['must_not'])) {
$body['query']['function_score']['query']['bool']['must_not'] = [];
}
......@@ -107,7 +110,7 @@ class Repository
'access_id' => ['0', '1', '2'],
],
];
} elseif ($opts['type'] === 'user') {
} elseif ($type === 'user') {
$body['query']['function_score']['query']['bool']['must'][] = [
'term' => [
'access_id' => '2',
......@@ -236,7 +239,7 @@ class Repository
}
}
if ($opts['type'] !== 'group' && $opts['access_id'] !== null) {
if ($type !== 'group' && $opts['access_id'] !== null) {
$body['query']['function_score']['query']['bool']['must'][] = [
'terms' => [
'access_id' => Text::buildArray($opts['access_id']),
......@@ -294,6 +297,14 @@ class Repository
}
}
if ($opts['exclude']) {
$body['query']['function_score']['query']['bool']['must_not'][] = [
'terms' => [
'guid' => Text::buildArray($opts['exclude']),
],
];
}
// firehose options
......@@ -338,9 +349,15 @@ class Repository
//
$esType = $opts['type'];
if ($esType === 'all') {
$esType = 'object:image,object:video,object:blog';
}
$query = [
'index' => $this->index,
'type' => $opts['type'],
'type' => $esType,
'body' => $body,
'size' => $opts['limit'],
'from' => $opts['offset'],
......
<?php
namespace Minds\Core\Payments\Stripe\Instances;
use Minds\Common\StaticToInstance;
use Minds\Core\Config\Config;
use Minds\Core\Di\Di;
/**
* @method ChargeInstance retrieve()
*/
class ChargeInstance extends StaticToInstance
{
public function __construct(Config $config = null)
{
$config = $config ?? Di::_()->get('Config');
\Stripe\Stripe::setApiKey($config->get('payments')['stripe']['api_key']);
$this->setClass(new \Stripe\Charge);
}
}
<?php
namespace Minds\Core\Payments\Stripe\Instances;
use Minds\Common\StaticToInstance;
use Minds\Core\Config\Config;
use Minds\Core\Di\Di;
/**
* @method TransferInstance all()
*/
class TransferInstance extends StaticToInstance
{
public function __construct(Config $config = null)
{
$config = $config ?? Di::_()->get('Config');
\Stripe\Stripe::setApiKey($config->get('payments')['stripe']['api_key']);
$this->setClass(new \Stripe\Transfer);
}
}
......@@ -63,6 +63,9 @@ class Manager
'transfer_data' => [
'destination' => $intent->getStripeAccountId(),
],
'metadata' => [
'user_guid' => $intent->getUserGuid(),
],
];
if ($intent->getServiceFee()) {
......
<?php
namespace Minds\Core\Payments\Stripe\Transactions;
use Minds\Core\Payments\Stripe\Connect\Account;
use Minds\Core\Payments\Stripe\Instances\TransferInstance;
use Minds\Core\Payments\Stripe\Instances\ChargeInstance;
use Minds\Core\Di\Di;
use Minds\Common\Repository\Response;
class Manager
{
/** @var EntitiesBuilder $entitiesBuilder */
private $entitiesBuilder;
/** @var TransferInstance $transferInstance */
private $transferInstance;
/** @var ChargeInstance $chargeInstance */
private $chargeInstance;
public function __construct($entitiesBuilder = null, $transferInstance = null, $chargeInstance = null)
{
$this->entitiesBuilder = $entitiesBuilder ?? Di::_()->get('EntitiesBuilder');
$this->transferInstance = $transferInstance ?? new TransferInstance();
$this->chargeInstance = $chargeInstance ?? new ChargeInstance();
}
/**
* Return transactions from an account object
* @param Account $account
* @return Response[Transaction]
*/
public function getByAccount(Account $account): Response
{
$transfers = $this->transferInstance->all([ 'destination' => $account->getId() ]);
$response = new Response();
foreach ($transfers->autoPagingIterator() as $transfer) {
try {
$payment = $this->chargeInstance->retrieve($transfer->source_transaction);
} catch (\Exception $e) {
continue;
}
$transaction = new Transaction();
$transaction->setId($transfer->id)
->setTimestamp($transfer->created)
->setGross($payment->amount)
->setFees(0)
->setNet($transfer->amount)
->setCurrency($transfer->currency)
->setCustomerUserGuid($payment->metadata['user_guid'])
->setCustomerUser($this->entitiesBuilder->single($payment->metadata['user_guid']));
$response[] = $transaction;
}
return $response;
}
}
<?php
namespace Minds\Core\Payments\Stripe\Transactions;
use Minds\Entities\User;
use Minds\Traits\MagicAttributes;
class Transaction
{
use MagicAttributes;
/** @var string $id */
private $id;
/** @var int $timestamp */
private $timestamp;
/** @var int $gross */
private $gross;
/** @var string $currency */
private $currency;
/** @var int $fees */
private $fees;
/** @var int $net */
private $net;
/** @var string $customerGuid */
private $customerUserGuid;
/** @var User $customerUser */
private $customerUser;
/**
* Expose to the public apis
* @param array $extend
* @return array
*/
public function export(array $extend = []) : array
{
return [
'id' => $this->id,
'timestamp' => $this->timestamp,
'gross' => $this->gross,
'currency' => $this->currency,
'fees' => $this->fees,
'net' => $this->net,
'customer_user_guid' => $this->userGuid,
'customer_user' => $this->customerUser ? $this->customerUser->export() : null,
];
}
}
<?php
namespace Minds\Core\Permissions\Delegates;
use Minds\Core\Permissions\Roles\Roles;
use Minds\Entities\User;
abstract class BaseRoleCalculator
{
/** @var Roles */
protected $roles;
/** @var User */
protected $user;
public function __construct(User $user, Roles $roles = null)
{
$this->roles = $roles ?: new Roles();
$this->user = $user;
}
abstract public function calculate($entity);
}
<?php
namespace Minds\Core\Permissions\Delegates;
use Minds\Traits\MagicAttributes;
use Minds\Core\Permissions\Roles\Roles;
use Minds\Core\Permissions\Roles\Role;
class ChannelRoleCalculator extends BaseRoleCalculator
{
use MagicAttributes;
private $channels = [];
/**
* Retrieves permissions for an entity relative to the user's role in a channel
* Retrieves the role from the in memory cache if we've seen this channel before during this request
* Else checks the user's membership against the channel.
*
* @param $entity an entity from a channel
*
* @return Role
*/
public function calculate($entity): Role
{
if (isset($this->channels[$entity->getOwnerGUID()])) {
return $this->channels[$entity->getOwnerGUID()];
}
$role = null;
if ($entity->getOwnerGUID() === $this->user->getGUID()) {
$role = $this->roles->getRole(Roles::ROLE_CHANNEL_OWNER);
} elseif ($this->user->isSubscribed($entity->getOwnerGUID())) {
$role = $this->roles->getRole(Roles::ROLE_CHANNEL_SUBSCRIBER);
} else {
$role = $this->roles->getRole(Roles::ROLE_CHANNEL_NON_SUBSCRIBER);
}
$this->channels[$entity->getOwnerGUID()] = $role;
return $role;
}
}
<?php
namespace Minds\Core\Permissions\Delegates;
use Minds\Traits\MagicAttributes;
use Minds\Core\Di\Di;
use Minds\Core\Permissions\Roles\Role;
use Minds\Core\EntitiesBuilder;
use Minds\Entities\User;
use Minds\Core\Permissions\Roles\Roles;
class GroupRoleCalculator extends BaseRoleCalculator
{
use MagicAttributes;
/** @var EntitiesBuilder */
private $entitiesBuilder;
/** @var array */
private $groups = [];
public function __construct(User $user, Roles $roles, EntitiesBuilder $entitiesBuilder = null)
{
parent::__construct($user, $roles);
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
}
/**
* Retrieves permissions for an entity relative to the user's role in a group
* Retrieves the role from the in memory cache if we've seen this group before during this request
* Else gets the group and checks the user's membership.
*
* @param $entity an entity belonging to a group
*
* @return Role
*/
public function calculate($entity): Role
{
if (isset($this->groups[$entity->getAccessId()])) {
return $this->groups[$entity->getAccessId()];
}
$group = $this->entitiesBuilder->single($entity->getAccessId());
$role = null;
if ($group->isCreator($this->user)) {
$role = $this->roles->getRole(Roles::ROLE_GROUP_OWNER);
} elseif ($group->isOwner($this->user)) {
$role = $this->roles->getRole(Roles::ROLE_GROUP_ADMIN);
} elseif ($group->isBanned($this->user)) {
$role = $this->roles->getRole(Roles::ROLE_BANNED);
} elseif ($group->isModerator($this->user)) {
$role = $this->roles->getRole(Roles::ROLE_GROUP_MODERATOR);
} elseif ($group->isMember($this->user)) {
$role = $this->roles->getRole(Roles::ROLE_GROUP_SUBSCRIBER);
} else {
$role = $this->roles->getRole(Roles::ROLE_GROUP_NON_SUBSCRIBER);
}
$this->groups[$entity->getAccessId()] = $role;
return $role;
}
}
<?php
namespace Minds\Core\Permissions\Entities;
use Minds\Traits\MagicAttributes;
/**
* Class Permissions
* @method Permissions setAllowComments(bool $allowComments)
* @method bool getAllowComments();
*/
class EntityPermissions
{
use MagicAttributes;
/** @var bool AllowComments */
private $allowComments = true;
}
<?php
namespace Minds\Core\Permissions\Entities;
use Minds\Core\Di\Di;
use Minds\Core\EntitiesBuilder;
use Minds\Core\Data\Call;
use Minds\Core\Entities\Actions\Save;
/*
* Manager for managing entity specific permissions
*/
class Manager
{
/** @var EntitiesBuilder $entitiesBuilder */
protected $entitiesBuilder;
/** @var Call */
protected $db;
/** @var Save */
protected $save;
public function __construct(
EntitiesBuilder $entitiesBuilder = null,
Call $db = null,
Save $save = null)
{
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->db = $db ?: new Call('entities_by_time');
$this->save = $save ?: new Save(); //Mockable, else instantiate a new one on save.
}
/**
* Save permissions for an entity and propegate it to linked objects.
*
* @param mixed $entity a minds entity that implements the save function
* @param Permissions $permissions the flag to apply to the entity
*/
public function save($entity, EntityPermissions $permissions): void
{
$entity->setAllowComments($permissions->getAllowComments());
$this->save
->setEntity($entity)
->save();
if (method_exists($entity, 'getType')
&& $entity->getType() == 'activity'
&& $entity->get('entity_guid')
) {
$attachment = $this->entitiesBuilder->single($entity->get('entity_guid'));
$attachment->setAllowComments($permissions->getAllowComments());
$this->save
->setEntity($attachment)
->save();
}
foreach ($this->db->getRow('activity:entitylink:'.$entity->getGUID()) as $parentGuid => $ts) {
$activity = $this->entitiesBuilder->single($parentGuid);
$activity->setAllowComments($permissions->getAllowComments());
$this->save
->setEntity($activity)
->save();
}
}
}
......@@ -3,61 +3,57 @@
namespace Minds\Core\Permissions;
use Minds\Core\Di\Di;
use Minds\Core\EntitiesBuilder;
use Minds\Core\Data\Call;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\Permissions\Permissions;
/*
* Manager for managing role based permissions
*/
class Manager
{
/** @var EntitiesBuilder $entitiesBuilder */
protected $entitiesBuilder;
/** @var Call */
protected $db;
/** @var Save */
protected $save;
public function __construct(
EntitiesBuilder $entitiesBuilder = null,
Call $db = null,
Save $save = null)
/** @var EntityBuilder */
private $entityBuilder;
public function __construct($entityBuilder = null)
{
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->db = $db ?: new Call('entities_by_time');
$this->save = $save ?: new Save(); //Mockable, else instantiate a new one on save.
}
/**
* Save permissions for an entity and propegate it to linked objects
* @param mixed $entity a minds entity that implements the save function
* @param Permissions $permissions the flag to apply to the entity
*/
public function save($entity, Permissions $permissions)
* Takes a user_guid and list of entity guids
* Builds up a permissions object
* Permissions contains the user's role per entity, channel and group.
*
* @param array $opts
* - user_guid: long, the user's guid for calculating permissions
* - guids: array long, the list of entities to permit
*
* @return Permissions A map of channels, groups and entities with the user's role for each
*/
public function getList(array $opts = []): Permissions
{
$entity->setAllowComments($permissions->getAllowComments());
$this->save
->setEntity($entity)
->save();
if (method_exists($entity, 'getType')
&& $entity->getType() == 'activity'
&& $entity->get('entity_guid')
) {
$attachment = $this->entitiesBuilder->single($entity->get('entity_guid'));
$attachment->setAllowComments($permissions->getAllowComments());
$this->save
->setEntity($attachment)
->save();
$opts = array_merge([
'user_guid' => null,
'guids' => [],
], $opts);
if ($opts['user_guid'] === null) {
throw new \InvalidArgumentException('user_guid is required');
}
$user = $this->entitiesBuilder->single($opts['user_guid']);
$entities = $this->entitiesBuilder->get($opts);
if ($user->getType() !== 'user') {
throw new \InvalidArgumentException('Entity is not a user');
}
foreach ($this->db->getRow('activity:entitylink:'.$entity->getGUID()) as $parentGuid => $ts) {
$activity = $this->entitiesBuilder->single($parentGuid);
$activity->setAllowComments($permissions->getAllowComments());
$this->save
->setEntity($activity)
->save();
$roles = new Roles();
/** @var Permissions */
$permissions = new Permissions($user, null, $entitiesBuilder);
if (is_array($entities)) {
$permissions->calculate($entities);
}
return $permissions;
}
}
......@@ -3,16 +3,143 @@
namespace Minds\Core\Permissions;
use Minds\Traits\MagicAttributes;
use Minds\Entities\User;
use Minds\Core\EntitiesBuilder;
use Minds\Core\Permissions\Roles\Roles;
use Minds\Core\Permissions\Roles\Role;
use Minds\Core\Permissions\Delegates\ChannelRoleCalculator;
use Minds\Core\Permissions\Delegates\GroupRoleCalculator;
use Minds\Common\Access;
use Minds\Core\Di\Di;
use Minds\Exceptions\ImmutableException;
/**
* Class Permissions
* @method Permissions setAllowComments(bool $allowComments)
* @method bool getAllowComments();
*/
class Permissions
class Permissions implements \JsonSerializable
{
use MagicAttributes;
/** @var bool AllowComments */
private $allowComments = true;
/** @var bool */
private $isAdmin = false;
/** @var bool */
private $isBanned = false;
/** @var User */
private $user;
/** @var Roles */
private $roles;
/** @var array */
private $entities;
/** @var ChannelRoleCalculator */
private $channelRoleCalculator;
/** @var GroupRoleCalculator */
private $groupRoleCalculator;
/** @var EntitiesBuilder */
private $entitiesBuilder;
public function __construct(User $user, Roles $roles = null, EntitiesBuilder $entitiesBuilder = null)
{
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->roles = $roles ?: new Roles();
$this->user = $user;
$this->isAdmin = $user->isAdmin();
$this->isBanned = $user->isBanned();
$this->groups = [];
$this->channels = [];
$this->entities = [];
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->channels[$user->getGUID()] = $user;
$this->channelRoleCalculator = new ChannelRoleCalculator($this->user, $this->roles);
$this->groupRoleCalculator = new GroupRoleCalculator($this->user, $this->roles, $entitiesBuilder);
}
/**
* Permissions are user aware. This bomb function is to keep the user from being changed after instantiation.
*
* @throws ImmutableException
*/
public function setUser(User $user): void
{
throw new ImmutableException('User can only be set in the constructor');
}
/**
* Takes an array of entities and checks their permissions
* Builds up collections of permissions based on the user's relationships to the entity
* Any found channels and their roles are accessible in the channelRoleCalculator
* Any found groups and their roles are in the groupRoleCalculator
* All requested entities and the user's role is available in $this->entities.
*
* @param array entities an array of entities for calculating permissions
*/
public function calculate(array $entities = []): void
{
foreach ($entities as $entity) {
$this->entities[$entity->getGUID()] = $this->getRoleForEntity($entity);
}
}
private function getRoleForEntity($entity): Role
{
$role = null;
//Access id is the best way to determine what the parent entity is
//Any of the access flags are a channel
//Anything else is a group guid
switch ($entity->getAccessId()) {
case Access::UNLISTED:
case Access::LOGGED_IN:
case Access::PUBLIC:
case Access::UNKNOWN:
$role = $this->channelRoleCalculator->calculate($entity);
break;
default:
$role = $this->groupRoleCalculator->calculate($entity);
}
//Apply global overrides
if ($this->isAdmin) {
$role = $this->roles->getRole(Roles::ROLE_ADMIN);
}
if ($this->isBanned) {
$role = $this->roles->getRole(Roles::ROLE_BANNED);
}
return $role;
}
/**
* Export the nested objects.
*
* @return array serialized objects
*/
public function export(): array
{
$export = [];
$export['user'] = $this->user->export();
$export['channels'] = $this->getChannels();
$export['groups'] = $this->getGroups();
$export['entities'] = $this->entities;
return $export;
}
/**
* @return array channel guids with the user's role
*/
public function getChannels(): array
{
return $this->channelRoleCalculator->getChannels();
}
/**
* @return array group guids with the user's role
*/
public function getGroups(): array
{
return $this->groupRoleCalculator->getGroups();
}
/**
* @return array serialized objects
*/
public function jsonSerialize(): array
{
return $this->export();
}
}
......@@ -3,11 +3,17 @@
namespace Minds\Core\Permissions;
use Minds\Core\Di\Provider as DiProvider;
use Minds\Core\Permissions\Entities;
use Minds\Core\Permissions\Manager;
class Provider extends DiProvider
{
public function register()
{
$this->di->bind('Permissions\Entities\Manager', function ($di) {
return new Entities\Manager();
});
$this->di->bind('Permissions\Manager', function ($di) {
return new Manager();
});
......
<?php
namespace Minds\Core\Permissions\Roles;
class AdminRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_ADMIN);
$this->addPermission(Roles::FLAG_APPOINT_ADMIN);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class BannedRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_BANNED);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
use Zend\Permissions\Rbac;
use Minds\Core\Permissions\Roles\Role;
abstract class BaseRole extends Rbac\Role implements \JsonSerializable, Role
{
public function export(): array
{
$export = [];
$export['name'] = $this->getName();
$export['permissions'] = $this->getPermissions();
return $export;
}
public function jsonSerialize(): array
{
return $this->export();
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class ChannelAdminRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_CHANNEL_ADMIN);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class ChannelModeratorRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_CHANNEL_MODERATOR);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class ChannelNonSubscriberRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_CHANNEL_NON_SUBSCRIBER);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class ChannelOwnerRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_CHANNEL_OWNER);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class ChannelSubscriberRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_CHANNEL_SUBSCRIBER);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class GroupAdminRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_GROUP_ADMIN);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class GroupModeratorRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_GROUP_MODERATOR);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class GroupNonSubscriberRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_GROUP_NON_SUBSCRIBER);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class GroupOwnerRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_GROUP_OWNER);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
class GroupSubscriberRole extends BaseRole
{
public function __construct()
{
parent::__construct(Roles::ROLE_GROUP_SUBSCRIBER);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
use Zend\Permissions\Rbac;
class LoggedOutRole extends Rbac\Role
{
public function __construct()
{
parent::__construct(Roles::ROLE_LOGGED_OUT);
}
}
<?php
namespace Minds\Core\Permissions\Roles;
interface Role
{
public function export();
}
<?php
namespace Minds\Core\Permissions\Roles;
use Zend\Permissions\Rbac\Rbac;
class Roles extends Rbac
{
public const ROLE_LOGGED_OUT = 'logged_out';
public const ROLE_BANNED = 'banned';
public const ROLE_ADMIN = 'admin';
public const ROLE_CHANNEL_ADMIN = 'channel_admin';
public const ROLE_CHANNEL_MODERATOR = 'channel_moderator';
public const ROLE_CHANNEL_OWNER = 'channel_owner';
public const ROLE_CHANNEL_SUBSCRIBER = 'channel_subscriber';
public const ROLE_CHANNEL_NON_SUBSCRIBER = 'channel_nonsubscriber';
public const ROLE_GROUP_ADMIN = 'group_admin';
public const ROLE_GROUP_MODERATOR = 'group_moderator';
public const ROLE_GROUP_OWNER = 'group_owner';
public const ROLE_GROUP_SUBSCRIBER = 'group_subscriber';
public const ROLE_GROUP_NON_SUBSCRIBER = 'group_nonsubscriber';
public const FLAG_APPOINT_ADMIN = 'appoint_admin';
public const FLAG_APPOINT_MODERATOR = 'appoint_moderator';
public const FLAG_APPROVE_SUBSCRIBER = 'approve_subscriber';
public const FLAG_CREATE_CHANNEL = 'create_channel';
public const FLAG_CREATE_COMMENT = 'create_comment';
public const FLAG_CREATE_GROUP = 'create_group';
public const FLAG_CREATE_POST = 'create_post';
public const FLAG_DELETE_CHANNEL = 'delete_channel';
public const FLAG_DELETE_COMMENT = 'delete_comment';
public const FLAG_DELETE_GROUP = 'delete_group';
public const FLAG_DELETE_POST = 'delete_post';
public const FLAG_EDIT_CHANNEL = 'edit_channel';
public const FLAG_EDIT_COMMENT = 'edit_comment';
public const FLAG_EDIT_GROUP = 'edit_group';
public const FLAG_EDIT_POST = 'edit_post';
public const FLAG_INVITE = 'invite';
public const FLAG_JOIN = 'join';
public const FLAG_JOIN_GATHERING = 'gathering';
public const FLAG_MESSAGE = 'message';
public const FLAG_SUBSCRIBE = 'subscribe';
public const FLAG_TAG = 'tag';
public const FLAG_REMIND = 'remind';
public const FLAG_WIRE = 'wire';
public const FLAG_VIEW = 'view';
public const FLAG_VOTE = 'vote';
public function __construct()
{
$this->addRole(new AdminRole());
$this->addRole(new BannedRole());
$this->addRole(new ChannelAdminRole());
$this->addRole(new ChannelModeratorRole());
$this->addRole(new ChannelNonSubscriberRole());
$this->addRole(new ChannelOwnerRole());
$this->addRole(new ChannelSubscriberRole());
$this->addRole(new GroupAdminRole());
$this->addRole(new GroupModeratorRole());
$this->addRole(new GroupNonSubscriberRole());
$this->addRole(new GroupOwnerRole());
$this->addRole(new GroupSubscriberRole());
}
}
......@@ -170,6 +170,7 @@ class Events
'xn--90aizihgi.xn--p1ai',
'tinyurl.com',
'bit.ly',
'bit.do',
'123football.space',
'bitly.com',
'j.mp',
......
......@@ -187,6 +187,7 @@ class Spam
'xn--90aizihgi.xn--p1ai',
'tinyurl.com',
'bit.ly',
'bit.do',
'123football.space',
'bitly.com',
'j.mp',
......
......@@ -266,7 +266,7 @@ class Manager
throw new \Exception("Not implemented ETH yet");
break;
case 'usd':
if (!$this->receiver->getMerchant() || $this->receiver->getMerchant()['id']) {
if (!$this->receiver->getMerchant() || !$this->receiver->getMerchant()['id']) {
throw new \Exception("This channel is not able to receive USD at the moment");
}
$intent = new PaymentIntent();
......
......@@ -540,7 +540,7 @@ class Group extends NormalizedEntity
*/
public function isBanned($user = null)
{
return (new Membership($this))->isInvited($user);
return Membership::_($this)->isBanned($user);
}
/**
......
This diff is collapsed.
<?php
namespace Minds\Exceptions;
/**
* Exception thrown by things that should be immutable.
*/
class ImmutableException extends \Exception
{
}
......@@ -7,6 +7,8 @@ use Minds\Core\Payments\Stripe\Connect\Account;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\Payments\Stripe\Connect\Delegates\NotificationDelegate;
use Minds\Core\Payments\Stripe\Instances\AccountInstance;
use Minds\Core\Payments\Stripe\Instances\BalanceInstance;
use Minds\Core\Payments\Stripe\Instances\FileInstance;
use Minds\Entities\User;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
......@@ -16,13 +18,17 @@ class ManagerSpec extends ObjectBehavior
private $save;
private $notificationDelegate;
private $accountInstance;
private $balanceInstance;
private $fileInstance;
public function let(Save $save, NotificationDelegate $notificationDelegate, AccountInstance $accountInstance)
public function let(Save $save, NotificationDelegate $notificationDelegate, AccountInstance $accountInstance, BalanceInstance $balanceInstance, FileInstance $fileInstance)
{
$this->beConstructedWith($save, $notificationDelegate, $accountInstance);
$this->beConstructedWith($save, $notificationDelegate, $accountInstance, $balanceInstance, $fileInstance);
$this->save = $save;
$this->notificationDelegate = $notificationDelegate;
$this->accountInstance = $accountInstance;
$this->balanceInstance = $balanceInstance;
$this->fileInstance = $fileInstance;
}
public function it_is_initializable()
......@@ -126,6 +132,31 @@ class ManagerSpec extends ObjectBehavior
'verification' => (object) [
'disabled_reason' => null,
],
'settings' => (object) [
'payouts' => (object) [
'schedule' => (object) [
'interval' => 1,
'delay_days' => 2,
'monthly_anchor' => 31,
],
],
],
]);
$this->balanceInstance->retrieve([ 'stripe_account' => 'acc_123'])
->willReturn((object) [
'pending' => [
(object) [
'amount' => 100,
'currency' => 'GBP',
],
],
'available' => [
(object) [
'amount' => 100,
'currency' => 'GBP',
],
],
]);
$account = $this->getByAccountId('acc_123');
......@@ -181,6 +212,31 @@ class ManagerSpec extends ObjectBehavior
'verification' => (object) [
'disabled_reason' => null,
],
'settings' => (object) [
'payouts' => (object) [
'schedule' => (object) [
'interval' => 1,
'delay_days' => 2,
'monthly_anchor' => 31,
]
]
]
]);
$this->balanceInstance->retrieve([ 'stripe_account' => 'acc_123'])
->willReturn((object) [
'pending' => [
(object) [
'amount' => 100,
'currency' => 'GBP',
],
],
'available' => [
(object) [
'amount' => 100,
'currency' => 'GBP',
],
],
]);
$user = new User();
......
<?php
namespace Spec\Minds\Core\Permissions;
namespace Spec\Minds\Core\Permissions\Entities;
use Minds\Core\Permissions\Manager;
use Minds\Core\Permissions\Permissions;
use Minds\Core\Permissions\Entities\Manager;
use Minds\Core\Permissions\Entities\EntityPermissions;
use Minds\Entities\User;
use PhpSpec\ObjectBehavior;
use Minds\Core\EntitiesBuilder;
......@@ -41,7 +41,7 @@ class ManagerSpec extends ObjectBehavior
public function it_should_save_entity_permissions(Entity $entity, Image $image)
{
$permissions = new Permissions();
$permissions = new EntityPermissions();
$entity->setAllowComments(true)->shouldBeCalled();
$entity->get('entity_guid')->shouldBeCalled()->willReturn(false);
$entity->getGUID()->shouldBeCalled()->willReturn(1);
......@@ -54,7 +54,7 @@ class ManagerSpec extends ObjectBehavior
public function it_should_save_attachment_permissions(Entity $entity, Image $image)
{
$permissions = new Permissions();
$permissions = new EntityPermissions();
$image->setAllowComments(true)->shouldBeCalled();
$this->entitiesBuilder->single(1)->shouldBeCalled()->willReturn($image);
$entity->setAllowComments(true)->shouldBeCalled();
......@@ -70,7 +70,7 @@ class ManagerSpec extends ObjectBehavior
public function it_should_save_linked_entity_permissions(Entity $entity, Entity $parent)
{
$permissions = new Permissions();
$permissions = new EntityPermissions();
$parent->setAllowComments(true)->shouldBeCalled();
$this->db->getRow('activity:entitylink:1')->shouldBeCalled()
->willReturn([2 => $parent]);
......
This diff is collapsed.
......@@ -6,6 +6,7 @@ use Minds\Entities\User;
use Minds\Core\Di\Di;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Minds\Common\ChannelMode;
class UserSpec extends ObjectBehavior
{
......@@ -51,4 +52,23 @@ class UserSpec extends ObjectBehavior
$this->setOnchainBooster(1560192357);
$this->isOnchainBooster()->shouldReturn(false);
}
public function it_should_have_a_default_mode_of_open()
{
$this->getMode()->shouldEqual(ChannelMode::OPEN);
}
public function it_should_assign_channel_modes()
{
$this->setMode(ChannelMode::CLOSED);
$this->getMode()->shouldEqual(ChannelMode::CLOSED);
$this->setMode(ChannelMode::MODERATED);
$this->getMode()->shouldEqual(ChannelMode::MODERATED);
}
public function it_should_export_values()
{
$export = $this->export()->getWrappedObject();
expect($export['mode'])->shouldEqual(ChannelMode::OPEN);
}
}
......@@ -33,7 +33,8 @@
"zendframework/zend-diactoros": "1.8.6",
"league/oauth2-server": "7.2.0",
"lcobucci/jwt": "3.2.4",
"sentry/sdk": "2.0.3"
"sentry/sdk": "2.0.3",
"zendframework/zend-permissions-rbac": "^3.0"
},
"repositories": [
{
......
......@@ -3381,6 +3381,17 @@
{
"name": "sentry/sdk",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php-sdk.git",
"reference": "91c36aec83e4c1c5801b64ef4927b78a5aa8ce7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php-sdk/zipball/91c36aec83e4c1c5801b64ef4927b78a5aa8ce7f",
"reference": "91c36aec83e4c1c5801b64ef4927b78a5aa8ce7f",
"shasum": ""
},
"require": {
"http-interop/http-factory-guzzle": "^1.0",
"php-http/curl-client": "^1.0|^2.0",
......@@ -4340,6 +4351,53 @@
],
"time": "2018-09-05T19:29:37+00:00"
},
{
"name": "zendframework/zend-permissions-rbac",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-permissions-rbac.git",
"reference": "b45da437ac91568491848323743548679a3df909"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-permissions-rbac/zipball/b45da437ac91568491848323743548679a3df909",
"reference": "b45da437ac91568491848323743548679a3df909",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.0.1",
"zendframework/zend-coding-standard": "~1.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev",
"dev-develop": "3.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Zend\\Permissions\\Rbac\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Provides a role-based access control management",
"homepage": "https://github.com/zendframework/zend-permissions-rbac",
"keywords": [
"ZendFramework",
"authorization",
"rbac",
"zend-permssions-rbac"
],
"time": "2019-06-25T06:15:10+00:00"
},
{
"name": "zircote/swagger-php",
"version": "2.x-dev",
......
......@@ -475,7 +475,8 @@ $CONFIG->set('features', [
'top-feeds' => true,
'cassandra-notifications' => true,
'dark-mode' => true,
'allow-comments-toggle' => false
'allow-comments-toggle' => false,
'permissions' => false
]);
$CONFIG->set('email', [
......
......@@ -5,7 +5,7 @@ rm -rf ../vendor
# Setup composer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
......