...
 
Commits (542)

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

image: minds/php:latest
services:
- docker:dind
image: minds/php:7.3
stages:
- build
- test
- deploy
cache:
paths:
- vendor
- bin
policy: pull
- prepare
- review
- deploy:staging
- qa
- deploy:canary
- deploy:production
build:
stage: build
script:
- apk update && apk add --no-cache git
- sh tools/setup.sh
cache:
- apk add --no-cache git
- sh tools/setup.sh production
artifacts:
name: '$CI_COMMIT_REF_SLUG'
paths:
- vendor
- bin
policy: push
test:
stage: test
image: php:7.1.11-fpm-alpine3.4 # TODO: Fix cassandra driver conflicts
image: minds/php:7.3
script:
- php -n -c Spec/php-test.ini bin/phpspec run
lint:
stage: test
image: minds/php:7.3
script:
- bin/php-cs-fixer fix --allow-risky=yes --verbose --dry-run
prepare:fpm:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- |
docker build \
-t $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID \
-f containers/php-fpm/Dockerfile \
--build-arg MINDS_VERSION=$CI_PIPELINE_ID \
--build-arg SENTRY_DSN=$SENTRY_DSN \
.
- docker push $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID
prepare:runners:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- apk update && apk add libpng-dev freetype-dev libjpeg-turbo-dev
- docker-php-ext-install mbstring
- docker-php-ext-install bcmath
- docker-php-ext-install gd
- bin/phpspec run
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- |
docker build \
-t $CI_REGISTRY_IMAGE/runners:$CI_PIPELINE_ID \
-f containers/php-runners/Dockerfile \
--build-arg MINDS_VERSION=$CI_PIPELINE_ID \
--build-arg SENTRY_DSN=$SENTRY_DSN \
.
- docker push $CI_REGISTRY_IMAGE/runners:$CI_PIPELINE_ID
prepare:all:sentry:
stage: prepare
image: getsentry/sentry-cli
script:
- echo "Create a new release $CI_PIPELINE_ID"
- sentry-cli releases new $CI_PIPELINE_ID
- sentry-cli releases set-commits --auto $CI_PIPELINE_ID
- sentry-cli releases finalize $CI_PIPELINE_ID
- echo "Finalized release for $CI_PIPELINE_ID"
review:start:
stage: review
image: minds/helm-eks:latest
script:
- aws eks update-kubeconfig --name=sandbox
- git clone --branch=master https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/minds/helm-charts.git
- echo "Upgrading helm for pipeline ${CI_PIPELINE_ID}"
- echo "Setting to image ${CI_REGISTRY_IMAGE}"
- "helm upgrade \
--install \
--reuse-values \
--set phpfpm.image.repository=$CI_REGISTRY_IMAGE/fpm \
--set-string phpfpm.image.tag=$CI_PIPELINE_ID \
--set runners.image.repository=$CI_REGISTRY_IMAGE/runners \
--set-string runners.image.tag=$CI_PIPELINE_ID \
--set domain=$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN \
--set elasticsearch.clusterName=$CI_BUILD_REF_SLUG-elasticsearch \
--wait \
$CI_BUILD_REF_SLUG \
./helm-charts/minds"
- sentry-cli releases deploys $CI_PIPELINE_ID new -e review-$CI_COMMIT_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
on_stop: review:stop
except:
refs:
- master
- test/gitlab-ci
review:stop:
stage: review
image: minds/helm-eks:latest
script:
- aws eks update-kubeconfig --name=sandbox
- helm del --purge $CI_BUILD_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
action: stop
variables:
GIT_STRATEGY: none
when: manual
except:
refs:
- master
- test/gitlab-ci
deploy:fpm:
stage: deploy
image: docker:latest
qa:manual:
stage: qa
script:
- apk add --no-cache curl jq python py-pip
- pip install awscli
- docker build -t $REPOSITORY_URL_FPM -f containers/php-fpm/Dockerfile .
- echo "Manually approved"
when: manual
only:
refs:
- master
- test/gitlab-ci
allow_failure: false
staging:fpm:
stage: deploy:staging
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="staging"
- $(aws ecr get-login --no-include-email --region us-east-1)
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID
# Push to AWS registry
- docker tag $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID $ECR_REPOSITORY_URL_FPM:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL_FPM:$IMAGE_LABEL
# Push to Gitlab registry
- docker tag $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID $CI_REGISTRY_IMAGE/fpm:$IMAGE_LABEL
- docker push $CI_REGISTRY_IMAGE/fpm:$IMAGE_LABEL
# Deploy to staging
- aws ecs update-service --service=$ECS_APP_STAGING_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
# Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e $IMAGE_LABEL
environment:
name: staging
url: https://www.minds.com/?staging=1
only:
refs:
- master
- test/gitlab-ci
canary:fpm:
stage: deploy:canary
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="canary"
- $(aws ecr get-login --no-include-email --region us-east-1)
- docker push $REPOSITORY_URL_FPM
- aws ecs update-service --service=$SERVICE_FPM --force-new-deployment --region us-east-1 --cluster=$CLUSTER
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID
# Push to AWS registry
- docker tag $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID $ECR_REPOSITORY_URL_FPM:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL_FPM:$IMAGE_LABEL
# Push to Gitlab registry
- docker tag $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID $CI_REGISTRY_IMAGE/fpm:$IMAGE_LABEL
- docker push $CI_REGISTRY_IMAGE/fpm:$IMAGE_LABEL
# Deploy to ECS
- aws ecs update-service --service=$ECS_APP_CANARY_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
# Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e $IMAGE_LABEL
only:
refs:
- master
- test/gitlab-ci
environment:
name: canary
url: https://www.minds.com/?canary=1 # requires canary cookie
when: manual
allow_failure: false # prevents auto deploy to full production
production:fpm:
stage: deploy:production
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="production"
- $(aws ecr get-login --no-include-email --region us-east-1)
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID
# Push to AWS registry
- docker tag $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID $ECR_REPOSITORY_URL_FPM:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL_FPM:$IMAGE_LABEL
# Push to Gitlab registry
- docker tag $CI_REGISTRY_IMAGE/fpm:$CI_PIPELINE_ID $CI_REGISTRY_IMAGE/fpm:$IMAGE_LABEL
- docker push $CI_REGISTRY_IMAGE/fpm:$IMAGE_LABEL
# Delpoy to ECS
- aws ecs update-service --service=$ECS_APP_PRODUCTION_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
# Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e $IMAGE_LABEL
only:
refs:
- master
- test/gitlab-ci
environment:
name: production
url: https://www.minds.com/
when: delayed
start_in: 12 hours # reduce? can always be deployed manually earlier too
deploy:runners:
stage: deploy
image: docker:latest
production:runners:
stage: deploy:production
image: minds/ci:latest
services:
- docker:dind
script:
- apk add --no-cache curl jq python py-pip
- pip install awscli
- docker build -t $REPOSITORY_URL_RUNNERS -f containers/php-runners/Dockerfile .
- IMAGE_LABEL="production"
- $(aws ecr get-login --no-include-email --region us-east-1)
- docker push $REPOSITORY_URL_RUNNERS
- aws ecs update-service --service=$SERVICE_RUNNERS --force-new-deployment --region us-east-1 --cluster=$CLUSTER
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/runners:$CI_PIPELINE_ID
# Push to production register
- docker tag $CI_REGISTRY_IMAGE/runners:$CI_PIPELINE_ID $ECR_REPOSITORY_URL_RUNNERS:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL_RUNNERS:$IMAGE_LABEL
# Push gitlab registry
- docker tag $CI_REGISTRY_IMAGE/runners:$CI_PIPELINE_ID $CI_REGISTRY_IMAGE/runners:$IMAGE_LABEL
- docker push $CI_REGISTRY_IMAGE/runners:$IMAGE_LABEL
- aws ecs update-service --service=$ECS_RUNNERS_PRODUCTION_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
only:
refs:
- master
- test/gitlab-ci
environment:
name: production
\ No newline at end of file
name: production
url: https://www.minds.com/
......@@ -5,5 +5,10 @@ $finder = PhpCsFixer\Finder::create()
->in(__DIR__);
return PhpCsFixer\Config::create()
->fixers(['psr2', 'strict_param', 'short_array_syntax', 'no_blank_lines_after_class_opening'])
->finder($finder);
->setRules([
'@PSR2' => true,
'strict_param' => true,
'array_syntax' => ['syntax' => 'short'],
'no_blank_lines_after_class_opening' => true,
])
->setFinder($finder);
......@@ -118,6 +118,10 @@ class Exportable implements \JsonSerializable
$exported['ownerObj']['guid'] = (string) $exported['ownerObj']['guid'];
}
if (isset($exported['urn']) && isset($_SERVER['HTTP_APP_VERSION'])) {
$exported['urn'] = "urn:entity:{$exported['guid']}";
}
foreach ($this->exceptions as $exception) {
$exported[$exception] = $item->{$exception};
}
......
......@@ -3,7 +3,6 @@
namespace Minds\Api;
use Minds\Interfaces;
use Minds\Helpers;
use Minds\Core\Security;
use Minds\Core\Session;
......@@ -32,6 +31,7 @@ class Factory
$loop = count($segments);
while ($loop >= 0) {
$offset = $loop -1;
if ($loop < count($segments)) {
$slug_length = strlen($segments[$offset+1].'\\');
$route_length = strlen($route);
......@@ -42,32 +42,51 @@ class Factory
$actual = str_replace('\\', '/', $route);
if (isset(Routes::$routes[$actual])) {
$class_name = Routes::$routes[$actual];
if (class_exists($class_name)) {
$handler = new $class_name();
if (property_exists($handler, 'request')) {
$handler->request = $request;
}
if ($handler instanceof Interfaces\ApiAdminPam) {
self::adminCheck();
}
if (!$handler instanceof Interfaces\ApiIgnorePam) {
self::pamCheck($request, $response);
}
$pages = array_splice($segments, $loop) ?: array();
$pages = array_splice($segments, $loop) ?: [];
return $handler->$method($pages);
}
}
//autloaded routes
$class_name = "\\Minds\\Controllers\api\\$route";
if (class_exists($class_name)) {
$handler = new $class_name();
if (property_exists($handler, 'request')) {
$handler->request = $request;
}
if ($handler instanceof Interfaces\ApiAdminPam) {
self::adminCheck();
}
if (!$handler instanceof Interfaces\ApiIgnorePam) {
self::pamCheck($request, $response);
}
$pages = array_splice($segments, $loop) ?: array();
$pages = array_splice($segments, $loop) ?: [];
return $handler->$method($pages);
}
--$loop;
}
}
......@@ -78,19 +97,28 @@ class Factory
*/
public static function pamCheck($request, $response)
{
if ( $request->getAttribute('oauth_user_id')
|| Security\XSRF::validateRequest()
if (
$request->getAttribute('oauth_user_id') ||
Security\XSRF::validateRequest()
) {
return true;
} else {
//error_log('failed authentication:: OAUTH via API');
ob_end_clean();
static::setCORSHeader();
$code = !Security\XSRF::validateRequest() ? 403 : 401;
if (isset($_SERVER['HTTP_APP_VERSION'])) {
$code = 401; // Mobile requires 401 errors
}
header('Content-type: application/json');
header("Access-Control-Allow-Origin: *");
header('HTTP/1.1 401 Unauthorized', true, 401);
http_response_code($code);
echo json_encode([
'error' => 'Sorry, you are not authenticated',
'code' => 401,
'error' => 'Sorry, you are not authenticated',
'code' => $code,
'loggedin' => false
]);
exit;
......@@ -108,10 +136,12 @@ class Factory
} else {
error_log('security: unauthorized access to admin api');
ob_end_clean();
static::setCORSHeader();
header('Content-type: application/json');
header("Access-Control-Allow-Origin: *");
header('HTTP/1.1 401 Unauthorized', true, 401);
echo json_encode(array('error'=>'You are not an admin', 'code'=>401));
echo json_encode(['error'=>'You are not an admin', 'code'=>401]);
exit;
}
}
......@@ -122,12 +152,14 @@ class Factory
*/
public static function isLoggedIn()
{
if(Session::isLoggedIn()){
if (Session::isLoggedIn()) {
return true;
} else {
ob_end_clean();
static::setCORSHeader();
header('Content-type: application/json');
header("Access-Control-Allow-Origin: *");
header('HTTP/1.1 401 Unauthorized', true, 401);
echo json_encode([
'status' => 'error',
......@@ -143,28 +175,46 @@ class Factory
* Builds an API response
* @param array $data
*/
public static function response($data = array())
public static function response($data = [])
{
$data = array_merge(array(
$data = array_merge([
'status' => 'success', //should success be assumed?
), $data);
], $data);
if (ob_get_level() > 1) {
// New PSR-7 Router has an OB started all the time
ob_end_clean();
}
ob_end_clean();
static::setCORSHeader();
header('Content-type: application/json');
header("Access-Control-Allow-Origin: *");
echo json_encode($data);
}
/**
* Sets the CORS header, if not already set
*/
public static function setCORSHeader(): void
{
$wasSet = count(array_filter(headers_list(), function ($header) {
return stripos($header, 'Access-Control-Allow-Origin:') === 0;
})) > 0;
if (!$wasSet) {
header("Access-Control-Allow-Origin: *");
}
}
/**
* Returns the exportable form of the entities
* @param array $entities - an array of entities
* @return array - an array of the entities
* @deprecated
*/
public static function exportable($entities, $exceptions = array(), $exportContext = false)
public static function exportable($entities, $exceptions = [], $exportContext = false)
{
if(!$entities){
if (!$entities) {
return [];
}
foreach ($entities as $k => $entity) {
......
......@@ -6,7 +6,7 @@ namespace Minds\Api;
*/
class Routes
{
public static $routes = array();
public static $routes = [];
/**
* Adds a custom API route resolution
......
......@@ -4,6 +4,7 @@ namespace Minds\Cli;
use ReflectionClass;
use ReflectionMethod;
use Minds\Exceptions\CliException;
/**
* CLI Controller.
......@@ -158,6 +159,16 @@ class Controller
return $this->opts;
}
public function gatekeeper($message = '')
{
$this->out(trim("{$message} Start operation?"), $this::OUTPUT_INLINE);
$answer = trim(readline('[y/N] '));
if ($answer != 'y') {
throw new CliException('Cancelled by user');
}
}
/**
* Gets the list of publically available commands and filters out the system ones.
*/
......
......@@ -61,11 +61,11 @@ class Factory
public static function toCamelNsp($namespace)
{
$namespace = explode('\\', $namespace);
$replacer = function($matches) {
$replacer = function ($matches) {
return strtoupper($matches[1]);
};
array_walk($namespace, function(&$segment) use ($replacer) {
array_walk($namespace, function (&$segment) use ($replacer) {
$segment = ucfirst(preg_replace_callback('/_([a-z])/', $replacer, $segment));
});
......
......@@ -6,7 +6,7 @@ namespace Minds\Cli;
*/
class Routes
{
public static $routes = array();
public static $routes = [];
/**
* Adds a custom CLI route resolution
......
<?php
namespace Minds\Common;
class Access
{
const UNLISTED = 0;
const LOGGED_IN = 1;
const PUBLIC = 2;
const UNKNOWN = 99;
const ACCESS_STRINGS = [
0 => 'Unlisted',
1 => 'LoggedIn',
3 => 'Public'
];
public static function idToString(int $id) : string
{
return self::ACCESS_STRINGS[$id] ?? 'Unknown';
}
}
<?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);
}
}
......@@ -8,16 +8,15 @@ use Minds\Traits\MagicAttributes;
/**
* Class Cookie
* @method Cookie setName(string $name)
* @method Cookie setValue(string $value)
* @method Cookie setValue(string $value)
* @method Cookie setExpire(int $value)
* @method Cookie setPath(string $path)
* @method Cookie setDomain(string $domain)
* @method Cookie setDomain(string $domain)
* @method Cookie setSecure(bool $secure)
* @method Cookie setHttpOnly(bool $httpOnly)
*/
class Cookie
{
use MagicAttributes;
/** @var CONFIG $config */
......@@ -71,5 +70,4 @@ class Cookie
setcookie($this->name, $this->value, $this->expire, $this->path, $this->domain, $this->secure, $this->httpOnly);
$_COOKIE[$this->name] = $this->value; //set the global cookie
}
}
<?php
/**
* Jwt
* @author edgebal
*/
namespace Minds\Common;
use Exception;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
class Jwt
{
/** @var string */
protected $key;
/**
* @param string $key
* @return Jwt
*/
public function setKey(string $key): Jwt
{
$this->key = $key;
return $this;
}
/**
* @param object|array $payload
* @param int|null $exp
* @param int|null $nbf
* @return string
* @throws Exception
*/
public function encode($payload, $exp = null, $nbf = null): string
{
if (!$this->key) {
throw new Exception('Invalid JWT key');
}
$builder = new Builder();
foreach ($payload as $key => $value) {
$builder->set($key, $value);
}
if ($exp !== null) {
$builder->setExpiration($exp);
}
if ($nbf !== null) {
$builder->setNotBefore($nbf);
}
$builder->sign(new Sha256(), $this->key);
return (string) $builder->getToken();
}
/**
* @param string $jwt
* @return array
* @throws Exception
*/
public function decode($jwt): array
{
if (!$this->key) {
throw new Exception('Invalid JWT key');
}
$token = (new Parser())->parse($jwt);
if (!$token->verify(new Sha256(), $this->key)) {
throw new Exception('Invalid JWT');
}
return array_map(function (Claim $claim) {
return $claim->getValue();
}, $token->getClaims());
}
/**
* @return string
*/
public function randomString(): string
{
$bytes = openssl_random_pseudo_bytes(128);
return hash('sha512', $bytes);
}
}
......@@ -259,6 +259,16 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
return count($this->data);
}
/**
* @param array $data
* @return Response
*/
public function pushArray(array $data)
{
array_push($this->data, ...$data);
return $this;
}
/**
* Exports the data array
* @return array
......@@ -328,4 +338,25 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
{
return array_reduce($this->data, $callback, $initialValue);
}
/**
* @param callable $callback
* @return Response
*/
public function sort(callable $callback): Response
{
$data = $this->data;
usort($data, $callback);
return new static($data, $this->pagingToken);
}
/**
* Returns the first element of the Response, or null if empty
* @return mixed|null
*/
public function first()
{
return $this->data[0] ?? null;
}
}
<?php
/**
* Converts a static class to use instances
*/
namespace Minds\Common;
use ReflectionClass;
use ReflectionException;
class StaticToInstance
{
/** @var ReflectionClass */
private $class;
/**
* StaticToInstance constructor.
* @param $class
* @throws ReflectionException
*/
public function __construct($class)
{
$this->setClass($class);
}
/**
* Set the class in question
* @param $class
* @return static
* @throws ReflectionException
*/
public function setClass($class)
{
$this->class = new ReflectionClass($class);
return clone $this;
}
/**
* Call the static functions as OO style
* @param string $method
* @param array $arguments
* @return mixed
*/
public function __call($method, $arguments)
{
$instance = $this->class->newInstanceWithoutConstructor();
return $instance::$method(...$arguments);
}
}
......@@ -9,7 +9,8 @@ use Minds\Core\Di\Di;
* @todo Create a BaseController class (to be used on Api, Cli, etc) with core DI operations.
* @todo Ensure this class is used EVERYWHERE on Minds\Controllers\api
*/
class Controller {
class Controller
{
protected $di;
protected $config;
......
......@@ -3,7 +3,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<style>
p {
p, li {
font-family: Roboto,Arial,sans-serif;
font-size: 18px;
line-height: 1.5;
......
......@@ -34,7 +34,6 @@ class AbuseGuard extends Cli\Controller implements Interfaces\CliControllerInter
$interval = $this->getOpt('interval') ?: 5;
while (true) {
$guard->setPeriod(
time() - (60 * 60 * 10),
time()
......@@ -50,7 +49,6 @@ class AbuseGuard extends Cli\Controller implements Interfaces\CliControllerInter
sleep($interval);
}
}
public function sync_single()
......
......@@ -2,6 +2,7 @@
namespace Minds\Controllers\Cli;
use Elasticsearch\Common\Exceptions\ServerErrorResponseException;
use Minds\Cli;
use Minds\Core;
use Minds\Entities;
......@@ -18,15 +19,18 @@ class Analytics extends Cli\Controller implements Interfaces\CliControllerInterf
case 'sync_activeUsers':
$this->out('Indexes user activity by guid and counts per day');
$this->out('--from={timestamp} the day to start counting. Default is yesterday at midnight');
$$his->out('--to={timestamp} the day to stop counting. Default is yesterday at midnight');
$this->out('--to={timestamp} the day to stop counting. Default is yesterday at midnight');
$this->out('--rangeOffset={number of days} the number of days to look back into the past. Default is 7');
$this->out('--mode={silent | notify} silent mode does not send emails when running batches to re-index. Notify sends the notifications. Default is notify');
break;
case 'sync_graphs':
$this->out('sync graphs between es and cassandra');
break;
case 'counts':
$this->out('Prints the counts of a user');
$this->out('--from={timestamp in milliseconds} the day to start count. Default is yesterday');
$this->out('--guid={user guid} REQUIRED the user to aggregate');
// no break
// no break
default:
$this->out('Syntax usage: cli analytics <type>');
$this->displayCommandHelp();
......@@ -50,7 +54,7 @@ class Analytics extends Cli\Controller implements Interfaces\CliControllerInterf
$this->out('Collecting user activity');
$this->out("Running in {$mode} mode");
while ($from <= $to) {
$this->out('Syncing for '.gmdate('c', $from));
$this->out('Syncing for ' . gmdate('c', $from));
$manager = new Core\Analytics\UserStates\Manager();
$manager->setReferenceDate($from)
->setRangeOffset($rangeOffset)
......@@ -79,4 +83,79 @@ class Analytics extends Cli\Controller implements Interfaces\CliControllerInterf
var_dump($result);
}
public function sync_graphs()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
/** @var Core\Analytics\Graphs\Manager $manager */
$manager = Core\Di\Di::_()->get('Analytics\Graphs\Manager');
$aggregates = [
'avgpageviews',
// 'interactions',
'offchainboosts',
'onchainboosts',
'offchainplus',
'onchainplus',
'offchainwire',
'onchainwire',
'activeusers',
'posts',
'votes',
'comments',
'reminds',
//'subscribers',
'totalpageviews',
'usersegments',
'pageviews',
'withdraw',
'tokensales',
'rewards',
];
if ($this->getOpt('aggregate')) {
$aggregates = [ $this->getOpt('aggregate') ];
}
foreach ($aggregates as $aggregate) {
$this->out("Syncing {$aggregate}");
try {
$manager->sync([
'aggregate' => $aggregate,
'all' => true,
]);
} catch (\Exception $e) {
}
}
$this->out('Completed caching site metrics');
}
public function syncViews()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$from = $this->getOpt('from') ?: strtotime('-7 days');
$opts = [
'from' => $from,
'day' => (int) date('d', $from),
];
$manager = new Core\Analytics\Views\Manager();
$i = 0;
$start = time();
foreach ($manager->syncToElastic($opts) as $view) {
$time = (new \Cassandra\Timeuuid($view->getUuid()))->time();
$date = date('d-m-Y h:i', $time);
$rps = (++$i) / ((time() - $start) ?: 1);
$this->out($i . "-{$view->getUuid()} {$date} ($rps/sec)");
}
$this->out('Done');
}
}
......@@ -46,7 +46,7 @@ class Blockchain extends Cli\Controller implements Interfaces\CliControllerInter
if (function_exists('pcntl_signal')) {
// Intercept Ctrl+C
pcntl_signal(SIGINT, function() {
pcntl_signal(SIGINT, function () {
$this->filterCleanup();
exit;
});
......@@ -106,7 +106,6 @@ class Blockchain extends Cli\Controller implements Interfaces\CliControllerInter
}
}
}
}
usleep(500 * 1000); // 500ms
......@@ -143,24 +142,24 @@ class Blockchain extends Cli\Controller implements Interfaces\CliControllerInter
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
while (true) {
$ethereum = Di::_()->get('Blockchain\Services\Ethereum');
$config = Di::_()->get('Config');
$ethRate = new EthRate;
$ethPrice = new EthPrice;
$ethPrice->setFrom(strtotime('24 hours ago'))
while (true) {
$ethereum = Di::_()->get('Blockchain\Services\Ethereum');
$config = Di::_()->get('Config');
$ethRate = new EthRate;
$ethPrice = new EthPrice;
$ethPrice->setFrom(strtotime('24 hours ago'))
->setTo(time())
->get();
$eth = round($ethPrice->getNearestPrice(strtotime('1 minute ago')));
$usd = 0.15;
$eth = round($ethPrice->getNearestPrice(strtotime('1 minute ago')));
$usd = 1.25;
$rate = round($eth/$usd);
if ($rate % 2 !== 0) {
$rate++;
}
$rate = round($eth/$usd);
if ($rate % 2 !== 0) {
$rate++;
}
$txHash = $ethereum->sendRawTransaction($config->blockchain['contracts']['token_sale_event']['rate_pkey'], [
$txHash = $ethereum->sendRawTransaction($config->blockchain['contracts']['token_sale_event']['rate_pkey'], [
'from' => $config->blockchain['contracts']['token_sale_event']['rate_address'],
'to' => $config->blockchain['contracts']['token_sale_event']['contract_address'],
'gasLimit' => BigNumber::_(200000)->toHex(true),
......@@ -170,31 +169,31 @@ while (true) {
])
]);
// Wait until mined before updating our backend
// Wait until mined before updating our backend
while (true) {
sleep(1);
$receipt = $ethereum->request('eth_getTransactionReceipt', [ $txHash ]);
echo "\n Waiting for $txHash";
if ($receipt && $receipt['status']) {
if ($receipt['status'] !== '0x1') {
echo "\n$txHash failed";
while (true) {
sleep(1);
$receipt = $ethereum->request('eth_getTransactionReceipt', [ $txHash ]);
echo "\n Waiting for $txHash";
if ($receipt && $receipt['status']) {
if ($receipt['status'] !== '0x1') {
echo "\n$txHash failed";
}
break;
}
break;
}
}
$ethRate->set($rate);
echo "\n Completed: new rate is $rate: $txHash";
echo "\n Now sleeping for one hour";
sleep(3600);
}
$ethRate->set($rate);
echo "\n Completed: new rate is $rate: $txHash";
echo "\n Now sleeping for one hour";
sleep(3600);
}
}
public function balance()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 1);
$username = $this->getOpt('username');
$user = new \Minds\Entities\User($username);
......
......@@ -14,7 +14,6 @@ use Minds\Core\Rewards\Contributions\UsersIterator;
class Contributions extends Cli\Controller implements Interfaces\CliControllerInterface
{
private $start;
private $elasticsearch;
......@@ -49,7 +48,7 @@ class Contributions extends Cli\Controller implements Interfaces\CliControllerIn
$this->out("Getting rewards for all users");
$total = 0;
$total = 0;
$i = 0;
foreach ($users as $guid) {
$i++;
......@@ -120,7 +119,7 @@ class Contributions extends Cli\Controller implements Interfaces\CliControllerIn
$hash = $user->getPhoneNumberHash();
if (isset($hashes[$hash])) { //don't allow multiple phones to claim checkin
$duplicates++;
$duplicates++;
continue;
}
$hashes[$hash] = true;
......@@ -143,7 +142,7 @@ class Contributions extends Cli\Controller implements Interfaces\CliControllerIn
->setUser($checkin['user'])
->issueCheckins($checkin['amount']);
}
}
}
public function test()
{
......@@ -162,7 +161,7 @@ class Contributions extends Cli\Controller implements Interfaces\CliControllerIn
->setDryRun(true);
if ($user->guid) {
$manager->setUser($user);
$manager->setUser($user);
}
$results = $manager->sync();
......@@ -171,9 +170,8 @@ class Contributions extends Cli\Controller implements Interfaces\CliControllerIn
foreach ($results as $result) {
$totals += $result->getAmount();
$totals_by_type[$result->getMetric()] += $result->getAmount();
}
}
var_dump($totals);
var_dump($totals_by_type);
}
}
......@@ -12,7 +12,6 @@ use Minds\Core\Analytics\Iterators\SignupsOffsetIterator;
class CreateFoundersIndex extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function help($command = null)
{
$this->out('TBD');
......@@ -21,7 +20,7 @@ class CreateFoundersIndex extends Cli\Controller implements Interfaces\CliContro
public function exec()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 1);
$db = Di::_()->get('Database\Cassandra\Cql');
$entities_by_time = new Core\Data\Call('entities_by_time');
......@@ -34,9 +33,8 @@ class CreateFoundersIndex extends Cli\Controller implements Interfaces\CliContro
echo "\n[$i]:$user->guid";
if ($user->founder) {
echo "\n[$i]:$user->guid indexed";
$entities_by_time->insert('user:founders', [ (string) $user->guid => (string) $user->guid ]);
$entities_by_time->insert('user:founders', [ (string) $user->guid => (string) $user->guid ]);
}
}
}
}
......@@ -12,7 +12,6 @@ use Stripe;
class CustomerSync extends Cli\Controller implements Interfaces\CliControllerInterface
{
private $db;
public function __construct()
......@@ -35,24 +34,25 @@ class CustomerSync extends Cli\Controller implements Interfaces\CliControllerInt
$this->db = Di::_()->get('Database\Cassandra\Cql'); //construct not being hit?
$fo = fopen("/home/ubuntu/customers.csv", "r");
$row = 0;
while (($data = fgetcsv($fo, 10000, ",")) !== FALSE) {
while (($data = fgetcsv($fo, 10000, ",")) !== false) {
$row++;
$id = $data[0];
$guid = $data[29];
try {
$insert = new Core\Data\Cassandra\Prepared\Custom();
$insert->query("INSERT INTO user_index_to_guid (key, column1, value) VALUES (?, ?, ?)",
[
$insert->query(
"INSERT INTO user_index_to_guid (key, column1, value) VALUES (?, ?, ?)",
[
"$guid:payments",
"customer_id",
$id
]);
]
);
$this->db->request($insert);
$this->out("$guid with customer id $id done");
} catch (\Exception $e) {
$this->out("$guid with customer id $id failed");
$this->out("$guid with customer id $id failed");
}
}
$this->out($count);
}
......
......@@ -34,18 +34,18 @@ class DWH extends Cli\Controller implements Interfaces\CliControllerInterface
$offset = "";
Core\Security\ACL::$ignore = false;
$i=0;
while(true){
while (true) {
echo "\n[$offset]: ";
$users = Core\Entities::get(['type'=>'user', 'limit' => $limit, 'offset'=>$offset]);
foreach($users as $user){
foreach ($users as $user) {
$i++;
$joined = date('d-m-Y h:i', $user->time_created);
echo "\n[$i/$joined]: $user->guid";
echo "\n[$i/$joined]: $user->guid";
$ts = Core\Analytics\Timestamps::get(['day', 'month'], $user->time_created);
//$db->insert("analytics:signup:day:{$ts['day']}", [$user->guid => $user->time_created]);
//$db->insert("analytics:signup:month:{$ts['month']}", [$user->guid => $user->time_created]);
}
if(count($users) < $limit/2){
if (count($users) < $limit/2) {
//break;
}
$offset = end($users)->guid;
......@@ -63,5 +63,4 @@ class DWH extends Cli\Controller implements Interfaces\CliControllerInterface
->increment();
$this->out('Done.');
}
}
......@@ -9,6 +9,7 @@ use Minds\Entities\User;
use Minds\Core\Email\Campaigns\UserRetention\GoneCold;
use Minds\Core\Email\Campaigns\WhenBoost;
use Minds\Core\Email\Campaigns\WireReceived;
use Minds\Core\Email\Campaigns\WirePromotions;
use Minds\Core\Email\Campaigns\UserRetention\WelcomeComplete;
use Minds\Core\Email\Campaigns\UserRetention\WelcomeIncomplete;
use Minds\Core\Suggestions\Manager;
......@@ -189,6 +190,28 @@ class Email extends Cli\Controller implements Interfaces\CliControllerInterface
}
}
public function testWirePromotion()
{
$userguid = $this->getOpt('guid');
$output = $this->getOpt('output');
$send = $this->getOpt('send');
$user = new User($userguid);
if (!$user->guid) {
$this->out('User not found');
exit;
}
$campaign = (new WirePromotions())
->setUser($user);
$message = $campaign->build();
if ($send) {
$campaign->send();
}
}
public function testWelcomeIncomplete()
{
$userguid = $this->getOpt('guid');
......
<?php
namespace Minds\Controllers\Cli;
use Minds\Core;
use Minds\Core\Analytics\EntityCentric\Manager;
use Minds\Cli;
use Minds\Interfaces;
use Minds\Exceptions;
use Minds\Entities;
class EntityCentric extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
{
}
public function help($command = null)
{
$this->out('TBD');
}
public function exec()
{
$this->out('Missing subcommand');
}
public function sync()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$daysAgo = $this->getOpt('daysAgo') ?: 0;
$from = $this->getOpt('from') ?: strtotime("midnight $daysAgo days ago");
$manager = new Manager();
$manager->setFrom($from);
$i = 0;
foreach ($manager->sync() as $record) {
$this->out(++$i .": {$record->getUrn()}");
}
}
}
......@@ -28,14 +28,13 @@ class GuidServer extends Cli\Controller implements Interfaces\CliControllerInter
$zks = 'localhost:2181';
$timer = new \Davegardnerisme\CruftFlake\Timer;
if ($machine !== NULL) {
$config = new \Davegardnerisme\CruftFlake\FixedConfig($machine);
if ($machine !== null) {
$config = new \Davegardnerisme\CruftFlake\FixedConfig($machine);
} else {
$config = new \Davegardnerisme\CruftFlake\ZkConfig($zks);
$config = new \Davegardnerisme\CruftFlake\ZkConfig($zks);
}
$generator = new \Davegardnerisme\CruftFlake\Generator($config, $timer);
$zmqRunner = new \Davegardnerisme\CruftFlake\ZeroMq($generator, $port);
$zmqRunner->run();
}
}
......@@ -18,8 +18,8 @@ class Install extends Cli\Controller implements Interfaces\CliControllerInterfac
{
$this->out('Configures web server and provisions and sets up databases for the minds application.');
$this->out('use-existing-settings: uses the existing settings in settings.php.');
$this->out('only=[keys|site|cassandra|cockroach] to set up individual components.');
$this->out('cleanCassandra cleanCockroach: deletes and recreates db.');
$this->out('only=[keys|site|cassandra|] to set up individual components.');
$this->out('cleanCassandra: deletes and recreates db.');
$this->out('graceful-storage-provision: causes installation to proceed past storage (db) failures.');
}
......@@ -52,7 +52,7 @@ class Install extends Cli\Controller implements Interfaces\CliControllerInterfac
$provisioner->checkOptions();
$this->out('OK');
// only=[keys|cassandra|cockroach|site]
// only=[keys|cassandra|site]
$installOnly = $this->getopt('only');
$installType = $installOnly ? $installOnly : "all";
......@@ -62,7 +62,7 @@ class Install extends Cli\Controller implements Interfaces\CliControllerInterfac
try {
if ($installType == "all" || $installType == "cassandra") {
$this->out('- Provisioning Cassandra: ', $this::OUTPUT_INLINE);
$this->out('- Provisioning Cassandra:', $this::OUTPUT_INLINE);
$isCleanCassandra = $this->getopt("cleanCassandra") != null;
$provisioner->provisionCassandra(null, $isCleanCassandra);
$this->out('OK');
......@@ -71,34 +71,8 @@ class Install extends Cli\Controller implements Interfaces\CliControllerInterfac
$provisioner->reloadStorage();
$this->out('OK');
}
} catch (Exception $e) {
// REVNOTE: This seems unused, currently. None of the database provisioners currently
// throw ProvisionException. We should maybe catch general exceptions (log them) and continue,
// and not ProvisionExceptions. I considered removing this altogether, but it is useful to continue
// past server errors in an setup.
if ($this->getOpt('graceful-storage-provision')) {
$this->out($e->getMessage());
$this->out('Error in cassandra setup. Continuing.');
} else {
throw $e;
}
}
try {
if ($installType == "all" || $installType == "cockroach") {
$this->out('- Provisioning Cockroach:', $this::OUTPUT_INLINE);
$isCleanCockroach = $this->getopt("cleanCockroach") != null;
$provisioner->provisionCockroach(null, $isCleanCockroach);
$this->out('OK');
}
} catch (Exception $e) {
// See REVNOTE above.
if ($this->getOpt('graceful-storage-provision')) {
$this->out($e->getMessage());
$this->out('Error in cockroach setup. Continuing.');
} else {
throw $e;
}
} catch (Exception $ex) {
$this->out('Something BAD happened while provisioning Cassandra' . $ex->getMessage());
}
if (($installType == "all") || ($installType == "site")) {
......@@ -106,9 +80,13 @@ class Install extends Cli\Controller implements Interfaces\CliControllerInterfac
$provisioner->setupSite();
$this->out('OK');
$this->out('- Setting up administrative user (ignore warnings, if any):', $this::OUTPUT_INLINE);
$provisioner->setupFirstAdmin();
$this->out('OK');
try {
$this->out('- Setting up administrative user (ignore warnings, if any):', $this::OUTPUT_INLINE);
$provisioner->setupFirstAdmin();
$this->out('OK');
} catch (\Exception $ex) {
$this->out('Could not setup initial user');
}
}
$this->out(['Done!', 'Open your browser and go to ' . $provisioner->getSiteUrl()], $this::OUTPUT_PRE);
......
......@@ -14,7 +14,6 @@ use Minds\Core\Analytics\Iterators\SignupsOffsetIterator;
class Boost extends Cli\Controller implements Interfaces\CliControllerInterface
{
private $db;
private $es;
......@@ -106,7 +105,7 @@ class Boost extends Cli\Controller implements Interfaces\CliControllerInterface
$body['@revoked'] = $export['last_updated'] * 1000;
} elseif ($boost->getState() === 'rejected') {
$body['@reviewed'] = $export['last_updated'] * 1000;
$body['@rejected'] = $export['last_updated'] * 1000;
$body['@rejected'] = $export['last_updated'] * 1000;
} elseif ($boost->getState() === 'completed') {
$body['@reviewed'] = $boost->getTimeCreated() * 1000;
$body['@completed'] = $export['last_updated'] * 1000;
......
......@@ -24,7 +24,8 @@ class Boosts extends Cli\Controller implements Interfaces\CliControllerInterface
$this->out('Syntax usage: cli migrations boosts [network|peer]');
}
public function exec() {
public function exec()
{
$this->out('Syntax usage: cli migrations boosts [network|peer]');
}
......@@ -73,7 +74,6 @@ class Boosts extends Cli\Controller implements Interfaces\CliControllerInterface
$this->out($done ? 'OK!' : 'Failed…');
}
}
}
}
......
......@@ -178,10 +178,10 @@ class Comments extends Cli\Controller implements Interfaces\CliControllerInterfa
$query->query($cql, $values);
if (!$dry) {
try {
try {
$this->client->request($query);
} catch (\Exception $e) {
var_dump($e);
var_dump($e);
}
}
}
......@@ -230,7 +230,7 @@ class Comments extends Cli\Controller implements Interfaces\CliControllerInterfa
// Poor-man's in memory json cache
static $jsonCache = [];
public static $jsonCache = [];
public static function _saveToJsonCache($key, $value)
{
......
......@@ -8,7 +8,6 @@ use Minds\Core;
use Minds\Entities\User;
use Minds\Interfaces;
class Emails extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
......@@ -32,4 +31,4 @@ class Emails extends Cli\Controller implements Interfaces\CliControllerInterface
$subscribeBatch->setOffset($offset)
->run();
}
}
\ No newline at end of file
}
......@@ -14,7 +14,6 @@ use Minds\Core\Data\Cassandra\Prepared;
use Cassandra;
class ImageDimensions extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
......@@ -39,12 +38,12 @@ class ImageDimensions extends Cli\Controller implements Interfaces\CliController
ini_set('display_errors', 1);
$guid = $this->getOpt('guid');
$this->update($guid);
$this->update($guid);
}
private function update($guid)
{
Core\Security\ACL::$ignore = true;
Core\Security\ACL::$ignore = true;
$thumbs = Di::_()->get('Media\Thumbnails');
$entity = new Activity($guid);
......@@ -73,7 +72,7 @@ class ImageDimensions extends Cli\Controller implements Interfaces\CliController
$entity->custom_data = $custom;
$entity->save();
$this->out("$entity->guid: Saved with w:$width h:$height");
}
}
}
public function activities()
......@@ -104,6 +103,5 @@ class ImageDimensions extends Cli\Controller implements Interfaces\CliController
$this->update($row['column1']);
}
}
}
}
......@@ -124,7 +124,6 @@ class Reports extends Cli\Controller implements Interfaces\CliControllerInterfac
$this->out($success ? 'OK' : 'Fail');
}
}
}
$this->out('Done!');
......
......@@ -57,7 +57,7 @@ class Search extends Cli\Controller implements Interfaces\CliControllerInterface
//
$client = Di::_()->get('Database\ElasticSearch');
$esIndex = Di::_()->get('Config')->elasticsearch['index'];
$esIndex = Di::_()->get('Config')->elasticsearch['index'];
/** @var Core\Data\Call $db */
......@@ -94,7 +94,7 @@ class Search extends Cli\Controller implements Interfaces\CliControllerInterface
$key .= ':' . $row['subtype'];
}
if (!in_array($key, $allowedTypes)) {
if (!in_array($key, $allowedTypes, true)) {
continue;
}
......@@ -154,20 +154,19 @@ class Search extends Cli\Controller implements Interfaces\CliControllerInterface
$client = Di::_()->get('Database\ElasticSearch');
$sFails = 0;
while(true){
$guids = $indexes->getRow($type, array('limit' => 750, 'offset' => $offset, 'reversed'=> true));
if(count($guids) <= 1)
while (true) {
$guids = $indexes->getRow($type, ['limit' => 750, 'offset' => $offset, 'reversed'=> true]);
if (count($guids) <= 1) {
break;
}
foreach($guids as $guid => $ts){
foreach ($guids as $guid => $ts) {
if ($sFails > 5) {
$this->out("Too many failures [pausing for 5 seconds]");
sleep(5);
}
try {
$entity = EntityFactory::build($guid);
$mapper = Di::_()->get('Search\Mappings')->build($entity);
......@@ -198,15 +197,10 @@ class Search extends Cli\Controller implements Interfaces\CliControllerInterface
echo " [failed]";
$sFails++;
}
}
end($guids);
$offset = key($guids);
}
}
}
......@@ -9,7 +9,6 @@ use Minds\Core\Hashtags\User\LegacyRepository;
use Minds\Core\Hashtags\User\Repository;
use Minds\Interfaces;
class UserHashtags extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function help($command = null)
......
......@@ -71,7 +71,7 @@ class Moderation extends Cli\Controller implements Interfaces\CliControllerInter
if (!$report) {
$this->out('Error: Invalid report');
exit(1);
} elseif($report->getState() !== 'initial_jury_decided') {
} elseif ($report->getState() !== 'initial_jury_decided') {
$this->out("Error: Report is not appealable. State is [{$report->getState()}].");
exit(1);
}
......@@ -151,7 +151,7 @@ class Moderation extends Cli\Controller implements Interfaces\CliControllerInter
->setJurorGuid((string) $user->guid)
->setStatus($respond);
$summonsManager->respond($summons);
$summonsManager->respond($summons);
$this->out("Responded to {$user->guid}'s summons to {$reportUrn} with {$respond}");
}
......
<?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?');
}
}
}
......@@ -25,5 +25,4 @@ class PDO extends Cli\Controller implements Interfaces\CliControllerInterface
$resp = $dwh->exec('SELECT * FROM suggested');
var_dump($resp);
}
}
<?php
namespace Minds\Controllers\Cli;
use Minds\Core;
use Minds\Core\Monetization\Partners\Manager;
use Minds\Cli;
use Minds\Interfaces;
use Minds\Exceptions;
use Minds\Entities;
class PartnerEarnings extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
{
}
public function help($command = null)
{
$this->out('TBD');
}
public function exec()
{
$this->out('Missing subcommand');
}
public function sync()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$daysAgo = $this->getOpt('daysAgo') ?: 0;
$from = $this->getOpt('from') ?: strtotime("midnight $daysAgo days ago");
$manager = new Manager();
$i = 0;
foreach ($manager->issueDeposits([ 'from' => $from ]) as $record) {
$this->out(++$i);
}
}
}
......@@ -7,8 +7,10 @@ use Minds\Core\Di\Di;
use Minds\Core\Events\Dispatcher;
use Minds\Core\Payments\Subscriptions\Manager;
use Minds\Core\Payments\Subscriptions\Queue;
use Minds\Core\Security\ACL;
use Minds\Helpers\Cql;
use Minds\Interfaces;
use Minds\Core\Util\BigNumber;
class Subscriptions extends Cli\Controller implements Interfaces\CliControllerInterface
{
......@@ -30,6 +32,8 @@ class Subscriptions extends Cli\Controller implements Interfaces\CliControllerIn
// Initialize events
\Minds\Core\Events\Defaults::_();
ACL::$ignore = true; // we need to save to channels
/** @var Manager $manager */
$manager = Di::_()->get('Payments\Subscriptions\Manager');
......@@ -42,6 +46,7 @@ class Subscriptions extends Cli\Controller implements Interfaces\CliControllerIn
foreach ($subscriptions as $subscription) {
$this->out("Subscription:`{$subscription->getId()}`");
$billing = date('d-m-Y', $subscription->getNextBilling());
$user_guid = $subscription->getUser()->guid;
$this->out("\t$billing | $user_guid");
......@@ -54,4 +59,143 @@ class Subscriptions extends Cli\Controller implements Interfaces\CliControllerIn
$this->out("Done");
}
public function repair()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
/** @var Manager $manager */
$manager = Di::_()->get('Payments\Subscriptions\Manager');
/** @var Queue $queue */
$subscriptions = Di::_()->get('Payments\Subscriptions\Iterator');
$subscriptions->setFrom(0)
->setPaymentMethod('tokens')
->setPlanId('wire');
foreach ($subscriptions as $subscription) {
$this->out("Subscription:`{$subscription->getId()}`");
if ($subscription->getId() === 'offchain') {
$this->out("Subscription:`{$subscription->getId()}` needs repairing");
$urn = "urn:subscription:" . implode('-', [
$subscription->getId(),
$subscription->getUser()->getGuid(),
$subscription->getEntity()->getGuid(),
]);
$this->out("Subscription:`{$subscription->getId()}` needs repairing to $urn");
$manager->setSubscription($subscription);
$manager->cancel();
$subscription->setId($urn);
$manager->setSubscription($subscription);
$manager->create();
}
if (strpos($subscription->getId(), '0x', 0) === 0) {
$this->out("Subscription:`{$subscription->getId()}` needs repairing");
$urn = "urn:subscription:" . implode('-', [
$subscription->getId(),
$subscription->getUser()->getGuid(),
$subscription->getEntity()->getGuid(),
]);
$this->out("Subscription:`{$subscription->getId()}` needs repairing to $urn");
$manager->setSubscription($subscription);
$manager->cancel();
$subscription->setId($urn);
$manager->setSubscription($subscription);
$manager->create();
}
}
$this->out("Done");
}
/**
* Sometimes, plus doesn't hit the delegate so the badge
* doesn't apply. This is designed to run regularly via
* a cron job to fix that
* @return void
*/
public function fixPlusWires()
{
ACL::$ignore = true; // we need to save to channels
$delegate = new \Minds\Core\Wire\Delegates\Plus;
$usersLastPlus = [];
foreach ($this->getWires(false) as $wire) {
$sender_guid = $wire->getSender()->getGuid();
$friendly = date('d-m-Y', $wire->getTimestamp());
echo "\n$sender_guid";
if ($wire->getTimestamp() < $usersLastPlus[$sender_guid] ?? time()) {
echo " $friendly already given plus to this user";
continue;
}
$usersLastPlus[$sender_guid] = $wire->getTimestamp();
$friendly = date('d-m-Y', $wire->getTimestamp());
echo " $friendly sending plus update ({$wire->getAmount()})";
if ($delegate->onWire($wire, 'offchain') || $delegate->onWire($wire, '0x6f2548b1bee178a49c8ea09be6845f6aeaf3e8da')) {
echo " done";
}
}
}
public function getWires($onchain = false)
{
$cql = \Minds\Core\Di\Di::_()->get('Database\Cassandra\Cql');
$prepared = new \Minds\Core\Data\Cassandra\Prepared\Custom;
$statement = "SELECT * FROM blockchain_transactions_mainnet WHERE contract='offchain:wire' and user_guid=? ALLOW FILTERING";
if ($onchain) {
$statement = "SELECT * FROM blockchain_transactions_mainnet WHERE wallet_address=? ALLOW FILTERING";
} else {
$statement = "SELECT * FROM blockchain_transactions_mainnet WHERE user_guid=? and amount>=? ALLOW FILTERING";
}
$offset = "";
while (true) {
if ($onchain) {
$prepared->query($statement, [ '0x6f2548b1bee178a49c8ea09be6845f6aeaf3e8da' ]);
} else {
$prepared->query($statement, [ new \Cassandra\Varint(730071191229833224), new \Cassandra\Varint(5) ]);
}
$prepared->setOpts([
'paging_state_token' => $offset,
'page_size' => 100,
]);
try {
$result = $cql->request($prepared);
if (!$result) {
break;
}
$offset = $result->pagingStateToken();
} catch (\Exception $e) {
var_dump($e);
}
foreach ($result as $row) {
$data = json_decode($row['data'], true);
if ($row['timestamp']->time() < strtotime('35 days ago')) {
return; // Do not sync old
}
if (!$data['sender_guid']) {
var_dump($row);
}
$wire = new \Minds\Core\Wire\Wire();
$wire
->setSender(new \Minds\Entities\User($data['sender_guid']))
->setReceiver(new \Minds\Entities\User($data['receiver_guid']))
->setEntity(\Minds\Entities\Factory::build($data['entity_guid']))
->setAmount((string) $data['amount'])
->setTimestamp((int) $row['timestamp']->time());
yield $wire;
}
}
}
}
......@@ -31,22 +31,22 @@ class Create extends Cli\Controller implements Interfaces\CliControllerInterface
"author" => $this->getOpt('author') ?: "Minds"
];
if(!$plugin['name']){
if (!$plugin['name']) {
throw new Exceptions\CliException("You must pass the --name option");
}
if(is_dir(str_replace('_template', $plugin['name'], $dir)) && !$this->getOpt('force')){
if (is_dir(str_replace('_template', $plugin['name'], $dir)) && !$this->getOpt('force')) {
throw new Exceptions\CliException("A plugin called {$plugin['name']} currently exists. Use the --force flag to replace");
}
foreach($files as $file){
foreach ($files as $file) {
$contents = file_get_contents($file);
$filename = str_replace('_template', $plugin['name'], $file);
$parts = explode('/', $filename);
array_pop($parts);
$parentDir = implode('/', $parts);
if(!is_dir($parentDir)) {
if (!is_dir($parentDir)) {
mkdir($parentDir, 0777, true);
}
......@@ -57,18 +57,15 @@ class Create extends Cli\Controller implements Interfaces\CliControllerInterface
file_put_contents($filename, $contents);
}
}
private function getFiles($dir)
{
$d = new \RecursiveDirectoryIterator($dir,\RecursiveDirectoryIterator::SKIP_DOTS);
$d = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
$return = [];
foreach(new \RecursiveIteratorIterator($d) as $file) {
foreach (new \RecursiveIteratorIterator($d) as $file) {
array_push($return, $file);
}
return $return;
......
......@@ -10,7 +10,6 @@ use Minds\Entities;
class RateLimits extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
{
$minds = new Core\Minds;
......@@ -50,7 +49,5 @@ class RateLimits extends Cli\Controller implements Interfaces\CliControllerInter
->impose();
var_dump($manager->isLimited());
}
}
......@@ -16,7 +16,6 @@ use Minds\Core\Events\Dispatcher;
class Rewards extends Cli\Controller implements Interfaces\CliControllerInterface
{
private $start;
private $elasticsearch;
......@@ -89,7 +88,7 @@ class Rewards extends Cli\Controller implements Interfaces\CliControllerInterfac
$fp = fopen("contributions-{$timestamp}.csv", 'w');
foreach($leaderboard as $guid => $count) {
foreach ($leaderboard as $guid => $count) {
fputcsv($fp, [ $guid, $count ]);
}
......@@ -130,5 +129,4 @@ class Rewards extends Cli\Controller implements Interfaces\CliControllerInterfac
$this->out('Issued');
}
}
......@@ -60,7 +60,6 @@ class Search extends Cli\Controller implements Interfaces\CliControllerInterface
$sync->sync($entity);
$this->out("$entity->guid [done]");
}
}
public function sync_single()
......
<?php
namespace Minds\Controllers\Cli;
use Minds\Cli;
use Minds\Core\Channels\Ban as ChannelsBanManager;
use Minds\Core\Channels\Manager as ChannelsManager;
use Minds\Core\Channels\Snapshots\Manager;
use Minds\Core\Channels\Snapshots\Snapshot as SnapshotEntity;
use Minds\Core\Di\Di;
use Minds\Core\Security\ACL;
use Minds\Entities\User;
use Minds\Exceptions\CliException;
use Minds\Interfaces;
class Snapshot extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
}
public function help($command = null)
{
$this->out([
'Syntax usage:',
'- cli snapshot [--and-ban] <user>',
'- cli snapshot restore <user GUID>',
'- cli snapshot dump <user GUID>',
]);
}
public function exec()
{
$shouldBan = $this->getOpt('and-ban');
if ($shouldBan) {
$this->gatekeeper('This is a destructive operation.');
}
ACL::$ignore = true;
$userIdentifier = $this->args[0] ?? null;
if (!$userIdentifier) {
return $this->help();
}
$user = new User($userIdentifier);
if (!$user || !$user->guid) {
throw new CliException('User not found');
}
$this->out("Creating snapshot for user [{$user->guid}]...");
//
/** @var ChannelsManager $channelsManager */
$channelsManager = Di::_()->get('Channels\Manager');
$channelsManager->setUser($user);
/** @var ChannelsBanManager $banManager */
$banManager = Di::_()->get('Channels\Ban');
$banManager->setUser($user);
//
$snapshotCreated = $channelsManager->snapshot();
if (!$snapshotCreated) {
throw new CliException('Error creating user snapshot.');
}
if ($shouldBan) {
$this->out('Created user snapshot! Deleting...');
$banned = $banManager->ban('Admin issued');
if (!$banned) {
throw new CliException('Error banning user.');
}
$cleanup = $banManager->banCleanup();
if (!$cleanup) {
throw new CliException('Error cleaning banned user\'s artifacts.');
}
$this->out('Banned!');
} else {
$this->out('Created user snapshot!');
}
return true;
}
public function restore()
{
$this->gatekeeper('This is a destructive operation.');
ACL::$ignore = true;
$userGuid = $this->args[0] ?? null;
if (!$userGuid) {
return $this->help();
}
/** @var ChannelsManager $channelsManager */
$channelsManager = Di::_()->get('Channels\Manager');
$snapshotRestored = $channelsManager->restore($userGuid);
if ($snapshotRestored) {
$this->out('Restored user snapshot!');
} else {
throw new CliException('Error restoring user snapshot.');
}
return true;
}
public function dump()
{
$userGuid = $this->args[0] ?? null;
if (!$userGuid) {
return $this->help();
}
$manager = new Manager();
$manager->setUserGuid($userGuid);
/** @var SnapshotEntity $snapshot */
foreach ($manager->getAll() as $snapshot) {
$this->out([
'Type: ' . $snapshot->getType(),
'Key : ' . implode(' -> ', explode("\t", $snapshot->getKey())),
'JSON: ' . $snapshot->getJsonData(true),
]);
$this->out(['', '---', '']);
}
}
}
<?php
namespace Minds\Controllers\Cli;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Cli;
use Minds\Interfaces;
use Minds\Exceptions;
use Minds\Entities;
use Minds\Core\Data\ElasticSearch\Prepared;
use Minds\Core\Analytics\Iterators\SignupsOffsetIterator;
use Minds\Core\Boost\Network\Manager;
use Minds\Core\Util\BigNumber;
use Minds\Helpers\Counters;
class Stripe extends Cli\Controller implements Interfaces\CliControllerInterface
{
private $db;
private $es;
private $elasticRepository;
private $pendingBulkInserts = [];
public function __construct()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
}
public function help($command = null)
{
$this->out('TBD');
}
public function exec()
{
echo "1";
}
public function get_payment_intent()
{
$intent = new Core\Payments\Stripe\Intents\PaymentIntent();
$intent->setAmount(2000);
$intentManager = new Core\Payments\Stripe\Intents\Manager();
$intent = $intentManager->add($intent);
var_dump($intent);
}
public function get_setup_intent()
{
$intent = new Core\Payments\Stripe\Intents\SetupIntent();
$intentManager = new Core\Payments\Stripe\Intents\Manager();
$intent = $intentManager->add($intent);
var_dump($intent->getClientSecret());
}
public function get_setup_intent_payment_method()
{
$id = $this->getOpt('id');
$intentManager = new Core\Payments\Stripe\Intents\Manager();
$intent = $intentManager->get($id);
var_dump($intent);
}
public function fix_connect()
{
$connectManager = new Core\Payments\Stripe\Connect\Manager();
$i = 0;
foreach ($connectManager->getList() as $account) {
++$i;
echo "\n$i $account->id";
var_dump($account->requirements->currently_due);
}
}
public function remove_business_type()
{
$connectManager = new Core\Payments\Stripe\Connect\Manager();
$account = $connectManager->getByAccountId($this->getOpt('id'));
$connectManager->update($account);
}
public function create_stripe_lookups()
{
$connectManager = new Core\Payments\Stripe\Connect\Manager();
$iterator = new Core\Analytics\Iterators\SignupsOffsetIterator();
$iterator->token = $this->getOpt('token');
$i = 0;
$s = 0;
foreach ($iterator as $user) {
if (!$user instanceof Entities\User) {
continue;
}
++$i;
var_dump($user->getMerchant());
if ($stripeId = $user->getMerchant()['id']) {
++$s;
}
echo "\n$s/$i $user->guid {$stripeId} ($iterator->token)";
if (!$stripeId) {
continue;
}
try {
$account = $connectManager->getByAccountId($stripeId);
$account->setEmail($user->getEmail());
$account->setUrl('https://www.minds.com/' . $user->username);
$account->setMetadata([
'guid' => (string) $user->guid,
]);
$connectManager->update($account);
} catch (\Exception $e) {
}
}
}
}
......@@ -12,7 +12,6 @@ use Stripe;
class SubscriptionSync extends Cli\Controller implements Interfaces\CliControllerInterface
{
private $db;
public function __construct()
......@@ -41,12 +40,11 @@ class SubscriptionSync extends Cli\Controller implements Interfaces\CliControlle
$plans = $this->db->request($query);
foreach ($plans as $plan) {
$opts = [];
if ($plan['entity_guid']) {
$entity = Entities\Factory::build($plan['entity_guid']);
if ($entity->type != 'user') {
$entity = $entity->getOwnerEntity();
$entity = $entity->getOwnerEntity();
}
$opts = [
'stripe_account' => $entity->getMerchant()['id']
......@@ -58,18 +56,21 @@ class SubscriptionSync extends Cli\Controller implements Interfaces\CliControlle
$amount = ($result->quantity * $result->plan->amount) / 100;
$insert = new Core\Data\Cassandra\Prepared\Custom();
$insert->query("INSERT INTO plans (user_guid, plan, entity_guid, amount) VALUES (?, ?, ?, ?)",
[
$insert->query(
"INSERT INTO plans (user_guid, plan, entity_guid, amount) VALUES (?, ?, ?, ?)",
[
$plan['user_guid'],
$plan['plan'],
$plan['entity_guid'],
(int) $amount
]);
]
);
$this->db->request($insert);
if ($plan['plan'] == 'exclusive') {
$query = new Core\Data\Cassandra\Prepared\Custom();
$query->query("INSERT INTO wire
$query->query(
"INSERT INTO wire
(receiver_guid, sender_guid, method, timestamp, entity_guid, wire_guid, amount, recurring, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
[
......@@ -82,7 +83,8 @@ class SubscriptionSync extends Cli\Controller implements Interfaces\CliControlle
new \Cassandra\Decimal($amount),
true,
'success'
]);
]
);
$this->db->request($query);
}
......@@ -91,7 +93,6 @@ class SubscriptionSync extends Cli\Controller implements Interfaces\CliControlle
} catch (\Exception $e) {
echo $e->getMessage() ."\n";
}
}
$this->out("Done");
......
<?php
namespace Minds\Controllers\Cli;
use Minds\Core\Minds;
use Minds\Cli;
use Minds\Core\Feeds\Suggested\Manager;
use Minds\Interfaces;
class Suggested extends Cli\Controller implements Interfaces\CliControllerInterface
{
/** @var Manager */
private $manager;
public function __construct()
{
$minds = new Minds();
$minds->start();
$this->manager = new Manager();
}
public function help($command = null)
{
$this->out('Syntax usage: cli trending <type>');
}
public function exec()
{
$this->out('Syntax usage: cli trending <type>');
}
public function sync_all()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$this->out('Collecting trending items');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('all');
$this->out('Completed syncing all');
}
public function sync_newsfeed()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$this->out('Syncing newsfeed');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('newsfeed');
$this->out('Completed syncing newsfeed');
}
public function sync_images()
{
$this->out('Syncing images');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('images');
$this->out('Completed syncing images');
}
public function sync_videos()
{
$this->out('Syncing videos');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('videos');
$this->out('Completed syncing videos');
}
public function sync_groups()
{
$this->out('Syncing groups');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('groups');
$this->out('Completed syncing groups');
}
public function sync_blogs()
{
$this->out('Syncing blogs');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('blogs');
$this->out('Completed syncing blogs');
}
}
......@@ -29,7 +29,6 @@ class Test extends Cli\Controller implements Interfaces\CliControllerInterface
]);
$this->out($namespace);
}
private function getTrendingActivities()
......@@ -43,8 +42,7 @@ class Test extends Cli\Controller implements Interfaces\CliControllerInterface
$activities = Core\Entities::get(array_merge([
'type' => 'activity'
]
, $options));
], $options));
$activities = array_filter($activities, function ($activity) {
if ($activity->paywall) {
......
......@@ -4,7 +4,7 @@ namespace Minds\Controllers\Cli;
use Minds\Core\Minds;
use Minds\Cli;
use Minds\Core\Feeds\Top\Manager;
use Minds\Core\Feeds\Elastic\Manager;
use Minds\Exceptions\CliException;
use Minds\Interfaces;
......
<?php
namespace Minds\Controllers\Cli\Top;
use Exception;
use Minds\Core\Feeds\Elastic\Sync;
use Minds\Core\Minds;
use Minds\Cli;
use Minds\Exceptions\CliException;
use Minds\Interfaces;
class All extends Cli\Controller implements Interfaces\CliControllerInterface
{
/** @var Sync */
private $sync;
/**
* Top constructor.
*/
public function __construct()
{
$minds = new Minds();
$minds->start();
$this->sync = new Sync();
}
/**
* @param null $command
* @return void
*/
public function help($command = null)
{
$this->out('Syntax usage: cli top all sync_<type> --metric=? --from=? --to=?');
}
/**
* @return void
*/
public function exec()
{
$this->help();
}
/**
* @throws CliException
*/
public function sync_activity(): void
{
list($from, $to) = $this->getTimeRangeFromArgs();
$this->syncBy('activity', null, $this->getOpt('metric'), $from, $to);
}
/**
* @throws CliException
*/
public function sync_images(): void
{
list($from, $to) = $this->getTimeRangeFromArgs();
$this->syncBy('object', 'image', $this->getOpt('metric'), $from, $to);
}
/**
* @throws CliException
*/
public function sync_videos(): void
{
list($from, $to) = $this->getTimeRangeFromArgs();
$this->syncBy('object', 'video', $this->getOpt('metric'), $from, $to);
}
/**
* @throws CliException
*/
public function sync_blogs(): void
{
list($from, $to) = $this->getTimeRangeFromArgs();
$this->syncBy('object', 'blog', $this->getOpt('metric'), $from, $to);
}
/**
* @throws CliException
*/
public function sync_groups(): void
{
list($from, $to) = $this->getTimeRangeFromArgs();
$this->syncBy('group', null, $this->getOpt('metric'), $from, $to);
}
/**
* @throws CliException
*/
public function sync_channels(): void
{
list($from, $to) = $this->getTimeRangeFromArgs();
$this->syncBy('user', null, $this->getOpt('metric'), $from, $to);
}
/**
* @return int[]
* @throws CliException
*/
protected function getTimeRangeFromArgs(): array
{
$to = $this->getOpt('to') ?: time();
if ($this->getOpt('from') && $this->getOpt('secsAgo')) {
throw new CliException('Cannot specify both `from` and `secsAgo`');
} elseif (!$this->getOpt('from') && !$this->getOpt('secsAgo')) {
throw new CliException('You should specify either `from` or `secsAgo`');
}
if ($this->getOpt('secsAgo')) {
$from = time() - $this->getOpt('secsAgo');
} else {
$from = $this->getOpt('from');
}
return [$from, $to];
}
/**
* @param $type
* @param $subtype
* @param $metric
* @param $from
* @param $to
* @throws CliException
* @throws Exception
*/
protected function syncBy($type, $subtype, $metric, $from, $to): void
{
if (!$metric) {
throw new CliException('Missing `metric`');
}
if (!$from || !is_numeric($from)) {
throw new CliException('Missing or invalid `from` value');
}
if (!$to || !is_numeric($to)) {
throw new CliException('Invalid `to` value');
}
if ($from > $to) {
throw new CliException('`from` must be lesser than `to`');
}
error_reporting(E_ALL);
ini_set('display_errors', 1);
$displayType = trim(implode(':', [$type, $subtype]), ':');
$this->out(sprintf(
"%s -> %s",
date('r', $from),
date('r', $to)
));
$this->out("Syncing {$displayType} / {$metric}");
$this->sync
->setType($type ?: '')
->setSubtype($subtype ?: '')
->setMetric($metric)
->setFrom($from * 1000)
->setTo($to * 1000)
->run();
$this->out("\nCompleted syncing '{$displayType}'.");
}
}
......@@ -18,11 +18,44 @@ class Transcode extends Cli\Controller implements Interfaces\CliControllerInterf
{
$this->out('TBD');
}
public function exec()
{
$transcoder = new Core\Media\Services\FFMpeg;
$transcoder->setKey($this->getOpt('guid'));
$transcoder->transcode();
$entity = Di::_()->get('EntitiesBuilder')->single($this->getOpt('guid'));
if (!$entity) {
$this->out('Entity not found');
return;
}
$manager = Di::_()->get('Media\Video\Transcoder\Manager');
$manager->createTranscodes($entity);
}
/**
* Retries the transcode on the current thread
* @return void
*/
public function retry()
{
$entity = Di::_()->get('EntitiesBuilder')->single($this->getOpt('guid'));
if (!$entity) {
$this->out('Entity not found');
return;
}
$manager = Di::_()->get('Media\Video\Transcoder\Manager');
$transcode = $manager->getList([
'guid' => $this->getOpt('guid'),
'profileId' => $this->getOpt('profile-id'),
])[0];
if (!$transcode) {
$this->out('Transcode not found');
return;
}
$manager->transcode($transcode);
}
}
......@@ -110,4 +110,4 @@ class Trending extends Cli\Controller implements Interfaces\CliControllerInterfa
Di::_()->get('Trending\Repository')->add('group', $guids);
$this->out("\nCollected " . count($guids) . ' groups');
}
}
\ No newline at end of file
}
......@@ -50,4 +50,52 @@ class User extends Cli\Controller implements Interfaces\CliControllerInterface
$this->out("Set feature flags for {$user->username}: " . implode(', ', $features));
}
}
/**
* Resets a users passwords.
* Requires username and password.
*
* Example call: php ./cli.php User password_reset --username=nemofin --password=password123
* @return void
*/
public function password_reset()
{
try {
if (!$this->getOpt('username') || !$this->getOpt('password')) {
throw new Exceptions\CliException('Missing username / password');
}
$username = $this->getOpt('username');
$password = $this->getOpt('password');
$user = new Entities\User($username);
$user->password = Core\Security\Password::generate($user, $password);
$user->password_reset_code = "";
$user->override_password = true;
$user->save();
$this->out("Password changed successfuly for user ".$username);
} catch (Exception $e) {
$this->out("An error has occured");
$this->out($e);
}
}
public function register_complete()
{
$username = $this->getOpt('username');
if (!$username) {
throw new Exceptions\CliException('Missing username');
}
$user = new Entities\User(strtolower($username));
if (!$user->guid) {
throw new Exceptions\CliException('User does not exist');
}
Core\Events\Dispatcher::trigger('register/complete', 'user', [ 'user' => $user ]);
}
}
......@@ -12,7 +12,7 @@ class wall extends core\page implements Interfaces\page
{
public function get($pages)
{
forward('fs/v1/thumbnail/' . $pages[1]);
forward('/fs/v1/thumbnail/' . $pages[1]);
}
public function post($pages)
......
......@@ -23,7 +23,7 @@ class active implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function get($pages)
{
$response = array();
$response = [];
$db = new Core\Data\Call('entities_by_time');
......@@ -44,7 +44,7 @@ class active implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -52,7 +52,7 @@ class active implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -60,6 +60,6 @@ class active implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -53,7 +53,7 @@ class boost implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -61,7 +61,7 @@ class boost implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -69,6 +69,6 @@ class boost implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -7,12 +7,11 @@ use Minds\Api\Factory;
use Minds\Core;
use Minds\Interfaces;
class pageviews implements Interfaces\Api, Interfaces\ApiAdminPam
{
public function get($pages)
{
$response = array();
$response = [];
$app = Core\Analytics\App::_()
->setMetric('pageview');
......@@ -38,5 +37,4 @@ class pageviews implements Interfaces\Api, Interfaces\ApiAdminPam
{
return Factory::response([]);
}
}
......@@ -23,7 +23,7 @@ class retention implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function get($pages)
{
$response = array();
$response = [];
$db = new Core\Data\Call('entities_by_time');
......@@ -41,7 +41,7 @@ class retention implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -49,7 +49,7 @@ class retention implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -57,6 +57,6 @@ class retention implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -23,7 +23,7 @@ class signups implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function get($pages)
{
$response = array();
$response = [];
$db = new Core\Data\Call('entities_by_time');
......@@ -43,7 +43,7 @@ class signups implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -51,7 +51,7 @@ class signups implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -59,6 +59,6 @@ class signups implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -57,35 +57,15 @@ class ban implements Interfaces\Api, Interfaces\ApiAdminPam
$json = file_get_contents("php://input");
$data = json_decode($json, true);
$ban_reason = $data['note'] ?: $data['subject']['label'];
$user->ban_reason = $data['note'] ?: $data['subject']['label'];
/** @var Core\Channels\Ban $channelsBanManager */
$channelsBanManager = Di::_()->get('Channels\Ban');
$user->banned = 'yes';
$user->code = '';
$user->save();
$channelsBanManager
->setUser($user)
->ban($ban_reason);
\cache_entity($user);
(new Core\Data\Sessions())->destroyAll($user->guid);
try {
$params = [
'index' => Config::_()->elasticsearch['index'],
'type' => 'user',
'id' => $user->guid
];
/** @var Core\Data\ElasticSearch\Client $elastic */
$elastic = Di::_()->get('Database\ElasticSearch');
$elastic->getClient()->delete($params);
} catch (\Exception $e) {
error_log(print_r($e->getMessage()));
}
Dispatcher::trigger('ban', 'user', $user);
return Factory::response([
'done' => true
]);
......@@ -110,11 +90,12 @@ class ban implements Interfaces\Api, Interfaces\ApiAdminPam
'error' => true
];
}
$user->banned = 'no';
$user->save();
\cache_entity($user);
/** @var Core\Channels\Ban $channelsBanManager */
$channelsBanManager = Di::_()->get('Channels\Ban');
$channelsBanManager
->setUser($user)
->unban();
return Factory::response([
'done' => true
......
......@@ -56,7 +56,7 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
$response = array();
$response = [];
$type = strtolower($pages[0]);
$guid = $pages[1];
......@@ -67,17 +67,17 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
$mature = isset($_POST['mature']) ? $_POST['mature'] : 0;
if (!$guid) {
return Factory::response(array(
return Factory::response([
'status' => 'error',
'message' => "We couldn't find that boost"
));
]);
}
if (!$action) {
return Factory::response(array(
return Factory::response([
'status' => 'error',
'message' => "You must provide an action: accept or reject"
));
]);
}
/** @var Core\Boost\Network\Review $review */
......@@ -106,7 +106,7 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
$dirty = false;
// explicit
if($reason == 1 || $mature) {
if ($reason == 1 || $mature) {
$dirty = $this->enableMatureFlag($entity);
}
......@@ -126,7 +126,6 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
$response['status'] = 'error';
$response['message'] = $e->getMessage();
}
} elseif ($action == 'reject') {
$review->setBoost($boost);
try {
......@@ -135,7 +134,7 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
$event->setAction('reject')
->setBoostRejectReason($reason)
->push();
} catch(\Exception $e) {
} catch (\Exception $e) {
$response['status'] = 'error';
$response['message'] = $e->getMessage();
}
......@@ -195,7 +194,7 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -203,6 +202,6 @@ class boosts implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -32,7 +32,7 @@ class delete implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($entity, 'getDeleted')) {
$isDeleted = $entity->getDeleted();
} else if (method_exists($entity, 'getFlag')) {
} elseif (method_exists($entity, 'getFlag')) {
$isDeleted = $entity->getFlag('deleted');
}
......@@ -64,7 +64,7 @@ class delete implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($entity, 'setDeleted')) {
$entity->setDeleted(true);
} else if (method_exists($entity, 'setFlag')) {
} elseif (method_exists($entity, 'setFlag')) {
$entity->setFlag('deleted', true);
} else {
return Factory::response([
......@@ -78,7 +78,7 @@ class delete implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($child, 'setDeleted')) {
$child->setDeleted(true);
} else if (method_exists($child, 'setFlag')) {
} elseif (method_exists($child, 'setFlag')) {
$child->setFlag('deleted', true);
}
......@@ -113,7 +113,7 @@ class delete implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($entity, 'setDeleted')) {
$entity->setDeleted(false);
} else if (method_exists($entity, 'setFlag')) {
} elseif (method_exists($entity, 'setFlag')) {
$entity->setFlag('deleted', false);
} else {
return Factory::response([
......@@ -127,7 +127,7 @@ class delete implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($child, 'setDeleted')) {
$child->setDeleted(false);
} else if (method_exists($child, 'setFlag')) {
} elseif (method_exists($child, 'setFlag')) {
$child->setFlag('deleted', false);
}
......
......@@ -22,7 +22,7 @@ class feature implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function get($pages)
{
$response = array();
$response = [];
return Factory::response($response);
}
......@@ -31,7 +31,7 @@ class feature implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -69,7 +69,7 @@ class feature implements Interfaces\Api, Interfaces\ApiAdminPam
$entity->save();
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -81,10 +81,10 @@ class feature implements Interfaces\Api, Interfaces\ApiAdminPam
$category = isset($pages[1]) ? $pages[1] : $entity->category;
if (!$entity) {
return Factory::response(array(
return Factory::response([
'status' => 'error',
'message' => "Entity not found"
));
]);
}
$entity->unFeature();
......@@ -96,6 +96,6 @@ class feature implements Interfaces\Api, Interfaces\ApiAdminPam
->setType($entity->subtype ?: $entity->type)
->remove($entity->guid);
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -65,5 +65,4 @@ class founder implements Interfaces\Api, Interfaces\ApiAdminPam
'done' => true
]);
}
}
......@@ -21,7 +21,7 @@ class monetize implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function get($pages)
{
$response = array();
$response = [];
return Factory::response($response);
}
......@@ -30,7 +30,7 @@ class monetize implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -42,16 +42,16 @@ class monetize implements Interfaces\Api, Interfaces\ApiAdminPam
$entity = Entities\Factory::build($pages[0]);
if (!$entity) {
return Factory::response(array(
return Factory::response([
'status' => 'error',
'message' => "Entity not found"
));
]);
}
$entity->monetized = true;
$entity->save();
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -62,15 +62,15 @@ class monetize implements Interfaces\Api, Interfaces\ApiAdminPam
$entity = Entities\Factory::build($pages[0]);
if (!$entity) {
return Factory::response(array(
return Factory::response([
'status' => 'error',
'message' => "Entity not found"
));
]);
}
$entity->monetized = false;
$entity->save();
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -78,11 +78,15 @@ class pages extends Controller implements Interfaces\Api, Interfaces\ApiIgnorePa
if (is_uploaded_file($_FILES['file']['tmp_name'])) {
$fs = Di::_()->get('Storage');
$dir = Di::_()->get('Config')->get('staticStorageFolder') ?: 'pages';
/** @var Core\Media\Imagick\Manager $manager */
$manager = Core\Di\Di::_()->get('Media\Imagick\Manager');
$resized = get_resized_image_from_uploaded_file('file', 2000, 10000);
$manager->setImage($_FILES['file']['tmp_name'])
->autorotate()
->resize(2000, 10000);
$fs->open("$dir/page_banners/{$page->getPath()}.jpg", '');
$fs->write($resized);
$fs->write($manager->getJpeg());
}
$page->setHeader(true)
......
......@@ -38,12 +38,12 @@ class paywall implements Interfaces\Api, Interfaces\ApiAdminPam
if ($guids) {
$entities = Core\Entities::get(['guids'=>$guids]);
foreach($entities as $k => $entity){
foreach ($entities as $k => $entity) {
$entities[$k]->paywall = false;
}
$response['entities'] = Factory::exportable($entities);
$response['load-next'] = (string) end($entities)->guid;
}
}
break;
}
......@@ -58,13 +58,13 @@ class paywall implements Interfaces\Api, Interfaces\ApiAdminPam
switch ($pages[1]) {
case "demonetize":
try {
return Factory::response([
return Factory::response([
'done' => (new Core\Payments\Plans\PaywallReview())
->setEntityGuid($pages[0])
->demonetize()
]);
} catch (\Exception $e) {
return Factory::response([
return Factory::response([
'status' => 'error',
'message' => $e->getMessage()
]);
......
......@@ -16,7 +16,7 @@ class purchases implements Interfaces\Api, Interfaces\ApiAdminPam
{
public function get($pages)
{
$offset = $_GET['offset'] ? base64_decode($_GET['offset']) : '';
$offset = $_GET['offset'] ? base64_decode($_GET['offset'], true) : '';
/** @var Core\Blockchain\Pledges\Repository $repo */
$repo = Di::_()->get('Blockchain\Purchase\Repository');
......@@ -123,5 +123,4 @@ class purchases implements Interfaces\Api, Interfaces\ApiAdminPam
'pledge' => $pledge->export(true)
]);
}
}
......@@ -75,6 +75,4 @@ class rating implements Interfaces\Api
{
return Factory::response([]);
}
}
\ No newline at end of file
}
......@@ -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
......
......@@ -32,7 +32,7 @@ class spam implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($entity, 'getSpam')) {
$isSpam = $entity->getSpam();
} else if (method_exists($entity, 'getFlag')) {
} elseif (method_exists($entity, 'getFlag')) {
$isSpam = $entity->getFlag('spam');
}
......@@ -64,7 +64,7 @@ class spam implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($entity, 'setSpam')) {
$entity->setSpam(true);
} else if (method_exists($entity, 'setFlag')) {
} elseif (method_exists($entity, 'setFlag')) {
$entity->setFlag('spam', true);
} else {
return Factory::response([
......@@ -78,7 +78,7 @@ class spam implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($child, 'setSpam')) {
$child->setSpam(true);
} else if (method_exists($child, 'setFlag')) {
} elseif (method_exists($child, 'setFlag')) {
$child->setFlag('spam', true);
}
......@@ -113,7 +113,7 @@ class spam implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($entity, 'setSpam')) {
$entity->setSpam(false);
} else if (method_exists($entity, 'setFlag')) {
} elseif (method_exists($entity, 'setFlag')) {
$entity->setFlag('spam', false);
} else {
return Factory::response([
......@@ -127,7 +127,7 @@ class spam implements Interfaces\Api, Interfaces\ApiAdminPam
if (method_exists($child, 'setSpam')) {
$child->setSpam(false);
} else if (method_exists($child, 'setFlag')) {
} elseif (method_exists($child, 'setFlag')) {
$child->setFlag('spam', false);
}
......
......@@ -15,7 +15,6 @@ use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
class tagcloud implements Interfaces\Api, Interfaces\ApiAdminPam
{
/**
......
......@@ -127,7 +127,7 @@ class analytics implements Interfaces\Api, Interfaces\ApiIgnorePam
break;
}
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
......
......@@ -10,11 +10,14 @@ namespace Minds\Controllers\api\v1;
use Minds\Core;
use Minds\Core\Security;
use Minds\Core\Session;
use Minds\Core\Features;
use Minds\Core\Di\Di;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Exceptions\TwoFactorRequired;
use Minds\Core\Queue;
use Minds\Core\Subscriptions;
class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
{
......@@ -23,7 +26,7 @@ class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
*/
public function get($pages)
{
return Factory::response(array('status'=>'error', 'message'=>'GET is not supported for this endpoint'));
return Factory::response(['status'=>'error', 'message'=>'GET is not supported for this endpoint']);
}
/**
......@@ -43,6 +46,7 @@ class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
}
$user = new Entities\User(strtolower($_POST['username']));
/** @var Core\Security\LoginAttempts $attempts */
$attempts = Core\Di\Di::_()->get('Security\LoginAttempts');
......@@ -87,7 +91,7 @@ class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
$response['code'] = $e->getCode();
$response['message'] = $e->getMessage();
return Factory::response($response);
}
}
$sessions = Di::_()->get('Sessions\Manager');
$sessions->setUser($user);
......@@ -96,9 +100,13 @@ class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
\set_last_login($user); // TODO: Refactor this
Session::generateJWTCookie($sessions->getSession());
Session::generateJWTCookie($sessions->getSession());
Security\XSRF::setCookie(true);
// Set the canary cookie
Di::_()->get('Features\Manager')
->setCanaryCookie($user->isCanary());
$response['status'] = 'success';
$response['user'] = $user->export();
......@@ -111,8 +119,9 @@ class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
public function delete($pages)
{
/** @var Core\Sessions\Manager $sessions */
$sessions = Di::_()->get('Sessions\Manager');
if (isset($pages[0]) && $pages[0] === 'all') {
$sessions->destroy(true);
} else {
......
......@@ -23,7 +23,7 @@ class block extends Controller implements Interfaces\Api
*/
public function get($pages)
{
$response = array();
$response = [];
if (!isset($pages[0])) {
$pages[0] = "list";
......@@ -67,7 +67,7 @@ class block extends Controller implements Interfaces\Api
*/
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -101,7 +101,7 @@ class block extends Controller implements Interfaces\Api
}
}
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -114,6 +114,6 @@ class block extends Controller implements Interfaces\Api
$block = $this->di->get('Security\ACL\Block');
$block->unBlock($pages[0]);
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -10,10 +10,11 @@ namespace Minds\Controllers\api\v1;
use Minds\Api\Exportable;
use Minds\Api\Factory;
use Minds\Common\Access;
use Minds\Core;
use Minds\Entities\Activity;
use Minds\Helpers;
use Minds\Interfaces;
use Minds\Core\Blogs\Delegates\CreateActivity;
class blog implements Interfaces\Api
{
......@@ -93,7 +94,7 @@ class blog implements Interfaces\Api
$export = [];
foreach ($blogs as $blog) {
if ($blog->getOwnerGuid() != Core\Session::getLoggedInUserGuid() && $blog->getAccessId() != 2) {
if ($blog->getOwnerGuid() != Core\Session::getLoggedInUserGuid() && $blog->getAccessId() != Access::PUBLIC) {
continue;
}
$export[] = $blog;
......@@ -127,7 +128,8 @@ class blog implements Interfaces\Api
try {
echo $header->read();
} catch (\Exception $e) { }
} catch (\Exception $e) {
}
exit;
......@@ -139,7 +141,10 @@ class blog implements Interfaces\Api
!$blog ||
Helpers\Flags::shouldFail($blog) ||
!Core\Security\ACL::_()->read($blog)
) break;
|| ($blog->getTimeCreated() > time() && !$blog->canEdit())
) {
break;
}
$response['blog'] = $blog;
}
......@@ -157,13 +162,16 @@ class blog implements Interfaces\Api
$header = new Core\Blogs\Header();
$response = [];
$alreadyPublished = false;
$oldAccessId = Access::UNKNOWN;
$editing = isset($pages[0]) && (is_numeric($pages[0]) || Core\Luid::isValid($pages[0]));
if ($editing) {
$blog = $manager->get($pages[0]);
$originallyPublished = $blog->isPublished();
$alreadyPublished = $blog->isPublished();
$oldAccessId = $alreadyPublished ? $blog->getAccessId() : $blog->getDraftAccessId();
} else {
$blog = new Core\Blogs\Blog();
$blog
......@@ -204,7 +212,7 @@ class blog implements Interfaces\Api
}
if (isset($_POST['tags']) && $_POST['tags'] !== '') {
$tags = !is_array($_POST['tags']) ? explode(',', $_POST['tags']) : $_POST['tags'];
$tags = !is_array($_POST['tags']) ? json_decode($_POST['tags']) : $_POST['tags'];
$blog->setTags($tags);
}
......@@ -212,12 +220,19 @@ class blog implements Interfaces\Api
$blog->setMature(!!$_POST['mature']);
}
if (isset($_POST['nsfw'])) {
$nsfw = !is_array($_POST['nsfw']) ? json_decode($_POST['nsfw']) : $_POST['nsfw'];
$blog->setNsfw($nsfw);
}
if (isset($_POST['wire_threshold'])) {
$blog->setWireThreshold($_POST['wire_threshold']);
$threshold = is_string($_POST['wire_threshold']) ? json_decode($_POST['wire_threshold']) : $_POST['wire_threshold'];
$blog->setWireThreshold($threshold);
}
if (isset($_POST['published'])) {
$blog->setPublished(!!$_POST['published']);
$published = is_string($_POST['published']) ? json_decode($_POST['published']) : $_POST['published'];
$blog->setPublished($published);
}
if (isset($_POST['monetized'])) {
......@@ -228,16 +243,12 @@ class blog implements Interfaces\Api
$blog->setSlug($_POST['slug']);
}
if (isset($_POST['custom_meta']) && is_array($_POST['custom_meta'])) {
$blog->setCustomMeta($_POST['custom_meta']);
}
if (isset($_POST['custom_meta'])) {
$meta = is_string($_POST['custom_meta']) ? json_decode($_POST['custom_meta'], true) : $_POST['custom_meta'];
//draft
if (!$_POST['published'] || $_POST['published'] === 'false') {
$blog->setAccessId(0);
$blog->setDraftAccessId($_POST['access_id']);
} elseif ($blog->getTimePublished() == '') {
$blog->setTimePublished(time());
if (is_array($meta)) {
$blog->setCustomMeta($meta);
}
}
$blog->setLastSave(time());
......@@ -260,7 +271,7 @@ class blog implements Interfaces\Api
}
if ($blog->isMonetized()) {
if ($blog->isMature()) {
if ($blog->getNsfw() || $blog->isMature()) {
return Factory::response([
'status' => 'error',
'message' => 'Cannot monetize an explicit blog'
......@@ -277,8 +288,8 @@ class blog implements Interfaces\Api
}
}
if (isset($_POST['mature']) && $_POST['mature']) {
if ((isset($_POST['nsfw']) && $_POST['nsfw'])
|| (isset($_POST['mature']) && $_POST['mature'])) {
$user = Core\Session::getLoggedInUser();
if (!$user->getMatureContent()) {
......@@ -287,6 +298,31 @@ class blog implements Interfaces\Api
}
}
if (isset($_POST['time_created'])) {
try {
$timeCreatedDelegate = new Core\Blogs\Delegates\TimeCreatedDelegate();
if ($editing) {
$timeCreatedDelegate->onUpdate($blog, $_POST['time_created'], time());
} else {
$timeCreatedDelegate->onAdd($blog, $_POST['time_created'], time());
}
} catch (\Exception $e) {
return Factory::response([
'status' => 'error',
'message' => $e->getMessage(),
]);
}
}
if (!$blog->isPublished()) {
$blog->setAccessId(Access::UNLISTED);
$blog->setDraftAccessId($_POST['access_id']);
} elseif ($blog->getTimePublished() == '') {
$blog->setTimePublished($blog->getTimeCreated() ?: time());
}
if (!$blog->canEdit()) {
return Factory::response([
'status' => 'error',
......@@ -301,6 +337,15 @@ class blog implements Interfaces\Api
]);
}
// This is a first create blog that should have a banner
// We are trying to stop spam with this check
if ($blog->isPublished() && !$editing && !is_uploaded_file($_FILES['file']['tmp_name'])) {
return Factory::response([
'status' => 'error',
'message' => 'You must upload a banner'
]);
}
try {
if ($editing) {
$saved = $manager->update($blog);
......@@ -315,26 +360,27 @@ class blog implements Interfaces\Api
}
if ($saved && is_uploaded_file($_FILES['file']['tmp_name'])) {
$image = get_resized_image_from_uploaded_file('file', 2000, 10000);
$header->write($blog, $image, isset($_POST['header_top']) ? (int) $_POST['header_top'] : 0);
/** @var Core\Media\Imagick\Manager $manager */
$manager = Core\Di\Di::_()->get('Media\Imagick\Manager');
try {
$manager->setImage($_FILES['file']['tmp_name'])
->resize(2000, 1000);
$header->write($blog, $manager->getJpeg(), isset($_POST['header_top']) ? (int)$_POST['header_top'] : 0);
} catch (\ImagickException $e) {
return Factory::response([
'status' => 'error',
'message' => 'Invalid image file',
]);
}
}
if ($saved) {
$createActivity = new Core\Blogs\Delegates\CreateActivity();
if (
!$editing &&
$blog->isPublished() &&
$blog->getAccessId() == 2
) {
$createActivity->save($blog);
} elseif (
$editing &&
!$originallyPublished &&
$blog->isPublished() &&
$blog->getAccessId() == 2
) {
$createActivity->save($blog);
if ($blog->isPublished() && in_array($blog->getAccessId(), [Access::PUBLIC, Access::LOGGED_IN], false)) {
if (!$editing || ($editing && !$alreadyPublished) || ($editing && $oldAccessId == Access::UNLISTED)) {
(new CreateActivity())->save($blog);
}
}
$response['guid'] = (string) $blog->getGuid();
......@@ -359,8 +405,10 @@ class blog implements Interfaces\Api
}
if (is_uploaded_file($_FILES['header']['tmp_name'])) {
$image = get_resized_image_from_uploaded_file('header', 2000, 10000);
$header->write($blog, $image, isset($_POST['header_top']) ? (int) $_POST['header_top'] : 0);
$manager->setImage($_FILES['header']['tmp_name'])
->resize(2000, 1000);
$header->write($blog, $manager->getJpeg(), isset($_POST['header_top']) ? (int) $_POST['header_top'] : 0);
}
return Factory::response([]);
......
......@@ -14,7 +14,6 @@ use Minds\Interfaces;
class boost implements Interfaces\Api
{
/**
* Equivalent to HTTP GET method
* @param array $pages
......
......@@ -18,7 +18,6 @@ use Minds\Interfaces;
class fetch implements Interfaces\Api
{
/**
* Return a list of boosts that a user needs to review
* @param array $pages
......@@ -178,32 +177,7 @@ class fetch implements Interfaces\Api
private function getSuggestedPosts($opts = [])
{
$opts = array_merge([
'offset' => 0,
'limit' => 12,
'rating' => 1,
], $opts);
/** @var Core\Feeds\Suggested\Manager $repo */
$repo = Di::_()->get('Feeds\Suggested\Manager');
$opts = [
'user_guid' => Core\Session::getLoggedInUserGuid(),
'rating' => $opts['rating'],
'limit' => $opts['limit'],
'offset' => $opts['offset'],
'type' => 'newsfeed',
'all' => true,
];
$result = $repo->getFeed($opts);
// Remove all unlisted content if it appears
$result = array_values(array_filter($result, function($entity) {
return $entity->getAccessId() != 0;
}));
return $result;
// @deprecated
return [];
}
}
......@@ -40,11 +40,11 @@ class captcha implements Interfaces\Api, Interfaces\ApiIgnorePam
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -22,7 +22,6 @@ class featured implements Interfaces\Api
*/
public function get($pages)
{
$repository = Di::_()->get('Categories\Repository');
$repository->setFilter('featured');
......@@ -30,7 +29,7 @@ class featured implements Interfaces\Api
$repository->setCategories(explode(',', $_GET['categories']));
}
switch($pages[0]){
switch ($pages[0]) {
case "object":
$repository->setType($pages[1]);
break;
......
......@@ -12,6 +12,8 @@ use Minds\Helpers;
use Minds\Interfaces;
use Minds\Entities;
use Minds\Api\Factory;
use Minds\Common\ChannelMode;
use Minds\Core\Di\Di;
use ElggFile;
class channel implements Interfaces\Api
......@@ -34,32 +36,36 @@ class channel implements Interfaces\Api
$user = new Entities\User($pages[0]);
if (!$user->username || Helpers\Flags::shouldFail($user)) {
return Factory::response(array('status'=>'error', 'message'=>'The user could not be found'));
return Factory::response(['status'=>'error', 'message'=>'The user could not be found']);
}
if ($user->enabled != "yes") {
return Factory::response(array('status'=>'error', 'message'=>'The user is disabled'));
return Factory::response(['status'=>'error', 'message'=>'The user is disabled']);
}
if ($user->banned == 'yes' && !Core\Session::isAdmin()) {
return Factory::response(array('status'=>'error', 'message'=>'The user is banned'));
return Factory::response(['status'=>'error', 'message'=>'The user is banned']);
}
Di::_()->get('Referrals\Cookie')
->setEntity($user)
->create();
$user->fullExport = true; //get counts
$user->exportCounts = true;
$return = Factory::exportable(array($user));
$return = Factory::exportable([$user]);
$response['channel'] = $return[0];
if (Core\Session::getLoggedinUser()->guid == $user->guid) {
$response['channel']['admin'] = $user->admin;
}
$response['channel']['avatar_url'] = array(
$response['channel']['avatar_url'] = [
'tiny' => $user->getIconURL('tiny'),
'small' => $user->getIconURL('small'),
'medium' => $user->getIconURL('medium'),
'large' => $user->getIconURL('large'),
'master' => $user->getIconURL('master')
);
];
$response['channel']['briefdescription'] = $response['channel']['briefdescription'] ?: '';
$response['channel']['city'] = $response['channel']['city'] ?: "";
......@@ -72,20 +78,33 @@ class channel implements Interfaces\Api
$response['channel']['activity_count'] = $feed_count;
}
$carousels = Core\Entities::get(array('subtype'=>'carousel', 'owner_guid'=>$user->guid));
$carousels = Core\Entities::get(['subtype'=>'carousel', 'owner_guid'=>$user->guid]);
if ($carousels) {
foreach ($carousels as $carousel) {
$response['channel']['carousels'][] = array(
$response['channel']['carousels'][] = [
'guid' => (string) $carousel->guid,
'top_offset' => $carousel->top_offset,
'src'=> Core\Config::_()->cdn_url . "fs/v1/banners/$carousel->guid/fat/$carousel->last_updated"
);
];
}
}
$block = Core\Security\ACL\Block::_();
$response['channel']['blocked'] = $block->isBlocked($user);
if ($user->isPro()) {
/** @var Core\Pro\Manager $manager */
$manager = Core\Di\Di::_()->get('Pro\Manager');
$manager
->setUser($user);
$proSettings = $manager->get();
if ($proSettings) {
$response['channel']['pro_settings'] = $proSettings;
}
}
return Factory::response($response);
}
......@@ -98,6 +117,9 @@ class channel implements Interfaces\Api
$guid = Core\Session::getLoggedinUser()->legacy_guid;
}
/** @var Core\Media\Imagick\Manager $manager */
$manager = Core\Di\Di::_()->get('Media\Imagick\Manager');
$response = [];
switch ($pages[0]) {
......@@ -105,17 +127,19 @@ class channel implements Interfaces\Api
$icon_sizes = Core\Config::_()->get('icon_sizes');
// get the images and save their file handlers into an array
// so we can do clean up if one fails.
$files = array();
$files = [];
foreach ($icon_sizes as $name => $size_info) {
$resized = get_resized_image_from_uploaded_file('file', $size_info['w'], $size_info['h'], $size_info['square'], $size_info['upscale']);
$manager->setImage($_FILES['file']['tmp_name'])
->autorotate()
->resize($size_info['w'], $size_info['h'], $size_info['upscale'], $size_info['square']);
if ($resized) {
if ($blob = $manager->getJpeg()) {
//@todo Make these actual entities. See exts #348.
$file = new ElggFile();
$file->owner_guid = Core\Session::getLoggedinUser()->guid;
$file->setFilename("profile/{$guid}{$name}.jpg");
$file->open('write');
$file->write($resized);
$file->write($blob);
$file->close();
$files[] = $file;
} else {
......@@ -157,12 +181,15 @@ class channel implements Interfaces\Api
$item->save();
if (is_uploaded_file($_FILES['file']['tmp_name'])) {
$resized = get_resized_image_from_uploaded_file('file', 2000, 10000);
$manager->setImage($_FILES['file']['tmp_name'])
->autorotate()
->resize(2000, 10000);
$file = new Entities\File();
$file->owner_guid = $item->owner_guid;
$file->setFilename("banners/{$item->guid}.jpg");
$file->open('write');
$file->write($resized);
$file->write($manager->getJpeg());
$file->close();
$response['uploaded'] = true;
......@@ -176,19 +203,22 @@ class channel implements Interfaces\Api
$item->last_updated = time();
$item->save();
$response['carousel'] = array(
$response['carousel'] = [
'guid' => (string) $item->guid,
'top_offset' => $item->top_offset,
'src'=> Core\Config::build()->cdn_url . "fs/v1/banners/$item->guid/fat/$item->last_updated"
);
];
if ($item->canEdit() && is_uploaded_file($_FILES['file']['tmp_name'])) {
$manager->setImage($_FILES['file']['tmp_name'])
->autorotate()
->resize(2000, 10000);
if (is_uploaded_file($_FILES['file']['tmp_name'])) {
$resized = get_resized_image_from_uploaded_file('file', 2000, 10000);
$file = new Entities\File();
$file->owner_guid = $item->owner_guid;
$file->setFilename("banners/{$item->guid}.jpg");
$file->open('write');
$file->write($resized);
$file->write($manager->getJpeg());
$file->close();
$response['uploaded'] = true;
......@@ -199,10 +229,10 @@ class channel implements Interfaces\Api
case "info":
default:
if (!$owner->canEdit()) {
return Factory::response(array('status'=>'error'));
return Factory::response(['status'=>'error']);
}
$update = array();
$update = [];
foreach (['name', 'website', 'briefdescription', 'gender',
'dob', 'city', 'coordinates', 'monetized'] as $field) {
if (isset($_POST[$field])) {
......@@ -211,6 +241,11 @@ class channel implements Interfaces\Api
}
}
if (isset($_POST['nsfw']) && is_array($_POST['nsfw'])) {
$nsfw = array_unique(array_merge($_POST['nsfw'], $owner->getNsfwLock()));
$update['nsfw'] = json_encode($nsfw);
$owner->setNsfw($nsfw);
}
if (isset($_POST['tags']) && $_POST['tags']) {
$update['tags'] = json_encode($_POST['tags']);
......@@ -226,6 +261,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 = [];
......@@ -264,7 +303,7 @@ class channel implements Interfaces\Api
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -273,7 +312,7 @@ class channel implements Interfaces\Api
public function delete($pages)
{
if (!Core\Session::getLoggedinUser()) {
return Factory::response(array('status' => 'error', 'message' => 'not logged in'));
return Factory::response(['status' => 'error', 'message' => 'not logged in']);
}
switch ($pages[0]) {
......@@ -288,17 +327,9 @@ class channel implements Interfaces\Api
$channel->enabled = 'no';
$channel->save();
$customer = (new Core\Payments\Customer())
->setUser($channel);
$stripe = Core\Di\Di::_()->get('StripePayments');
$customer = $stripe->getCustomer($customer);
if ($customer) {
$stripe->deleteCustomer($customer);
}
(new Core\Data\Sessions())->destroyAll($channel->guid);
}
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -29,15 +29,15 @@ class comments implements Interfaces\Api
public function get($pages)
{
//Factory::isLoggedIn();
$response = array();
$response = [];
$guid = $pages[0];
$parent_guid_l1 = $parent_guid_l2 = 0;
if(isset($_GET['parent_guid_l1']) && $_GET['parent_guid_l1'] != 0) {
if (isset($_GET['parent_guid_l1']) && $_GET['parent_guid_l1'] != 0) {
$parent_guid_l1 = $_GET['parent_guid_l1'];
}
if(isset($_GET['parent_guid_l2']) && $_GET['parent_guid_l2'] != 0) {
if (isset($_GET['parent_guid_l2']) && $_GET['parent_guid_l2'] != 0) {
$parent_guid_l2 = $_GET['parent_guid_l2'];
}
......@@ -92,15 +92,22 @@ class comments implements Interfaces\Api
{
$manager = new Core\Comments\Manager();
$response = array();
$response = [];
$error = false;
$emitToSocket = false;
switch ($pages[0]) {
case "update":
$comment = $manager->getByLuid($pages[1]);
if (!$comment || !$comment->canEdit()) {
$response = array('status' => 'error', 'message' => 'This comment can not be edited');
$canEdit = $comment->canEdit();
if ($canEdit && $comment->getOwnerGuid() != Core\Session::getLoggedInUserGuid()) {
$canEdit = false;
}
if (!$comment || !$canEdit) {
$response = ['status' => 'error', 'message' => 'This comment can not be edited'];
break;
}
......@@ -137,11 +144,11 @@ class comments implements Interfaces\Api
break;
case is_numeric($pages[0]):
default:
$entity = new \Minds\Entities\Entity($pages[0]);
$entity = Core\Di\Di::_()->get('EntitiesBuilder')->single($pages[0]);
if ($entity instanceof Entities\Activity && $entity->remind_object) {
$entity = (object) $entity->remind_object;
}
// if ($entity instanceof Entities\Activity && $entity->remind_object) {
// $entity = (object) $entity->remind_object;
// }
if (!$pages[0] || !$entity || $entity->type == 'comment') {
return Factory::response([
......@@ -150,17 +157,17 @@ class comments implements Interfaces\Api
]);
}
if (!$_POST['comment'] && !$_POST['attachment_guid']) {
if (method_exists($entity, 'getAllowComments') && !$entity->getAllowComments()) {
return Factory::response([
'status' => 'error',
'message' => 'You must enter a message'
'status' => 'error',
'message' => 'Comments are disabled for this post'
]);
}
if ($entity instanceof Entities\Activity && !$entity->commentsEnabled) {
if (!$_POST['comment'] && !$_POST['attachment_guid']) {
return Factory::response([
'status' => 'error',
'message' => 'Comments are disabled for this post'
'message' => 'You must enter a message'
]);
}
......@@ -193,7 +200,13 @@ class comments implements Interfaces\Api
$comment->setParentGuidL2($_POST['parentGuidL2']);
}
if ($entity->type == 'group') {
if ($entity instanceof Entities\Group) {
if ($entity->isConversationDisabled()) {
return Factory::response([
'status' => 'error',
'message' => 'Conversation has been disabled for this group',
]);
}
$comment->setGroupConversation(true);
}
......@@ -316,7 +329,8 @@ class comments implements Interfaces\Api
'reply',
(string) ($comment->getParentGuidL2() ?: $comment->getParentGuidL1())
);
} catch (\Exception $e) { }
} catch (\Exception $e) {
}
}
return Factory::response($response);
......@@ -333,15 +347,22 @@ class comments implements Interfaces\Api
$comment = $manager->getByLuid($pages[0]);
if ($comment && $comment->canEdit()) {
if (!$comment) {
return Factory::response([
'status' => 'error',
'message' => 'Comment not found',
]);
}
if ($comment->canEdit()) {
$manager->delete($comment);
return Factory::response([]);
}
//check if owner of activity trying to remove
$entity = Entities\Factory::build($comment->getEntityGuid());
if ($entity->owner_guid == Core\Session::getLoggedInUserGuid()) {
$manager->delete($comment, [ 'force' => true ]);
$manager->delete($comment, ['force' => true]);
return Factory::response([]);
}
......
......@@ -17,15 +17,18 @@ use Minds\Core\Sockets;
class disable implements Interfaces\Api
{
public function get($pages) {
public function get($pages)
{
return Factory::response([]);
}
public function post($pages) {
public function post($pages)
{
return Factory::response([]);
}
public function put($pages) {
public function put($pages)
{
$response = [];
if (is_numeric($pages[0])) {
......@@ -40,13 +43,13 @@ class disable implements Interfaces\Api
} else {
$response = ['entity' => $activity->export()];
}
}
return Factory::response($response);
}
public function delete($pages) {
public function delete($pages)
{
$response = [];
if (is_numeric($pages[0])) {
......@@ -64,5 +67,4 @@ class disable implements Interfaces\Api
return Factory::response($response);
}
}
......@@ -42,16 +42,16 @@ class neo implements Interfaces\Api
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
{
$activity = new Entities\Activity($pages[0]);
if (!$activity->guid) {
return Factory::response(array('status'=>'error', 'message'=>'could not find activity post'));
return Factory::response(['status'=>'error', 'message'=>'could not find activity post']);
}
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -25,7 +25,7 @@ class warehouse implements Interfaces\Api
\Minds\Core\Data\Warehouse\Factory::build(array_shift($pages))->run($pages);
$end = microtime();
return Factory::response(array('took'=>$end-$start));
return Factory::response(['took'=>$end-$start]);
}
public function post($pages)
......@@ -34,16 +34,16 @@ class warehouse implements Interfaces\Api
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
{
$activity = new Entities\Activity($pages[0]);
if (!$activity->guid) {
return Factory::response(array('status'=>'error', 'message'=>'could not find activity post'));
return Factory::response(['status'=>'error', 'message'=>'could not find activity post']);
}
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -76,8 +76,9 @@ class entities implements Interfaces\Api
switch ($pages[0]) {
case "all":
$type="user";
if (!Core\Session::isAdmin())
if (!Core\Session::isAdmin()) {
exit;
}
break;
case "container":
$owner = $pages[2];
......@@ -141,7 +142,7 @@ class entities implements Interfaces\Api
}
// Remove all unlisted content if it appears
$entities = array_values(array_filter($entities, function($entity) {
$entities = array_values(array_filter($entities, function ($entity) {
return $entity->getAccessId() != 0;
}));
......
......@@ -21,7 +21,7 @@ class explicit implements Interfaces\Api
{
public function get($pages)
{
return Factory::response(array());
return Factory::response([]);
}
/**
......@@ -35,7 +35,7 @@ class explicit implements Interfaces\Api
$entity = Entities\Factory::build($pages[0]);
if (!$entity->canEdit()) {
return Factory::response(array('status' => 'error', 'message' => 'Can´t edit this Post'));
return Factory::response(['status' => 'error', 'message' => 'Can´t edit this Post']);
}
$value = (bool) $_POST['value'];
......@@ -47,7 +47,7 @@ class explicit implements Interfaces\Api
$isAdmin = Session::isAdmin();
if ($matureLock && !$isAdmin) {
return Factory::response([
return Factory::response([
'status' => 'error',
'message' => 'You can not remove the mature flag from your channel',
]);
......@@ -70,7 +70,7 @@ class explicit implements Interfaces\Api
} else {
// mature locked channels are not allowed to remove explicit
if ($value === false && Session::getLoggedInUser()->getMatureLock()) {
return Factory::response(array('status' => 'error', 'message' => 'You can not remove the explicit flag'));
return Factory::response(['status' => 'error', 'message' => 'You can not remove the explicit flag']);
}
if (Helpers\MagicAttributes::setterExists($entity, 'setMature')) {
......@@ -123,11 +123,11 @@ class explicit implements Interfaces\Api
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
......@@ -78,12 +78,12 @@ class featured implements Interfaces\Api, Interfaces\ApiIgnorePam
}
//the allowed, plus default, options
$options = array(
$options = [
'type' => $type,
'subtype' => $subtype,
'limit'=>12,
'offset'=>get_input('offset', '')
);
];
foreach ($options as $key => $value) {
if (isset($_GET[$key])) {
......@@ -98,7 +98,7 @@ class featured implements Interfaces\Api, Interfaces\ApiIgnorePam
$guids = core\Data\indexes::fetch($key, $options);
if (!$guids) {
return Factory::response(array('status'=>'error', 'message'=>'not found'));
return Factory::response(['status'=>'error', 'message'=>'not found']);
}
if (isset($_GET['offset']) && $_GET['offset']) {
......
......@@ -36,8 +36,12 @@ class report implements Interfaces\Api
/** @var Core\Reports\Repository $repository */
$repository = Di::_()->get('Reports\Repository');
$done = $repository->create($pages[0], Core\Session::getLoggedinUser(),
$reason, $reason_note);
$done = $repository->create(
$pages[0],
Core\Session::getLoggedinUser(),
$reason,
$reason_note
);
return Factory::response([
'done' => $done
......
......@@ -73,17 +73,17 @@ class suggested implements Interfaces\Api, Interfaces\ApiIgnorePam
$rows = $result->getRows();
}
$guids = array();
$guids = [];
foreach ($rows['object'] as $object) {
$guids[] = $object['guid'];
}
if (!$guids) {
//show trending videos
$options = array(
$options = [
'timespan' => get_input('timespan', 'day')
);
];
$trending = new \MindsTrending(null, $options);
$guids = $trending->getList(array('type'=>'object', 'subtype'=>'kaltura_video', 'limit'=>6));
$guids = $trending->getList(['type'=>'object', 'subtype'=>'kaltura_video', 'limit'=>6]);
}
break;
case 'images':
......@@ -96,7 +96,7 @@ class suggested implements Interfaces\Api, Interfaces\ApiIgnorePam
$rows = $result->getRows();
}
$guids = array();
$guids = [];
foreach ($rows['object'] as $object) {
$guids[] = $object['guid'];
}
......@@ -113,14 +113,14 @@ class suggested implements Interfaces\Api, Interfaces\ApiIgnorePam
$result = false;
}
if (!$result) {
return Factory::response(array('status'=>'error', 'message'=>'not found'));
return Factory::response(['status'=>'error', 'message'=>'not found']);
}
} else {
$result= Data\Client::build('Neo4j')->requestRead($prepared->getSubscriptionsOfSubscriptions(Core\Session::getLoggedInUser(), $_GET['skip']));
}
$rows = $result->getRows();
$guids = array();
$guids = [];
if (isset($rows['fof'])) {
foreach ($rows['fof'] as $fof) {
$guids[] = $fof['guid'];
......@@ -129,7 +129,7 @@ class suggested implements Interfaces\Api, Interfaces\ApiIgnorePam
}
if (!$guids) {
return Factory::response(array('status'=>'error', 'message'=>'not found'));
return Factory::response(['status'=>'error', 'message'=>'not found']);
}
$options['guids'] = $guids;
......@@ -146,7 +146,7 @@ class suggested implements Interfaces\Api, Interfaces\ApiIgnorePam
$diff = microtime(true) - $ts;
//error_log("loaded suggested entities in $diff");
if ($entities) {
$response['entities'] = factory::exportable($entities, array('boosted'));
$response['entities'] = factory::exportable($entities, ['boosted']);
$response['load-next'] = (string) end($entities)->guid;
$response['load-previous'] = (string) key($entities)->guid;
}
......
......@@ -58,7 +58,7 @@ class trending implements Interfaces\Api, Interfaces\ApiIgnorePam
{
//temp hack..
//if(isset($pages[1]) && $pages[1] == 'video')
// $pages[1] = 'kaltura_video';
// $pages[1] = 'kaltura_video';
if (!isset($pages[1])) {
$pages[1] = $pages[0];
}
......@@ -125,7 +125,7 @@ class trending implements Interfaces\Api, Interfaces\ApiIgnorePam
}
ksort($result['guids']);
$entities = core\Entities::get(array('guids'=>$result['guids']));
$entities = core\Entities::get(['guids'=>$result['guids']]);
$response['entities'] = Factory::exportable($entities);
$response['load-next'] = base64_encode($result['token']);
......
......@@ -20,7 +20,7 @@ class forgotpassword implements Interfaces\Api, Interfaces\ApiIgnorePam
*/
public function get($pages)
{
return Factory::response(array('status'=>'error', 'message'=>'GET is not supported for this endpoint'));
return Factory::response(['status'=>'error', 'message'=>'GET is not supported for this endpoint']);
}
/**
......@@ -35,7 +35,7 @@ class forgotpassword implements Interfaces\Api, Interfaces\ApiIgnorePam
*/
public function post($pages)
{
$response = array();
$response = [];
if (!isset($pages[0])) {
$pages[0] = "request";
......@@ -94,6 +94,17 @@ class forgotpassword implements Interfaces\Api, Interfaces\ApiIgnorePam
break;
}
try {
if (!validate_password($_POST['password'])) {
$response['status'] = "error";
$response['message'] = "Password must have more than 8 characters. Including uppercase, numbers, special characters (ie. !,#,@), and cannot have spaces.";
}
} catch (\Exception $e) {
$response['status'] = "error";
$response['message'] = "Password must have more than 8 characters. Including uppercase, numbers, special characters (ie. !,#,@), and cannot have spaces.";
break;
}
//$user->salt = Core\Security\Password::salt();
$user->password = Core\Security\Password::generate($user, $_POST['password']);
$user->password_reset_code = "";
......@@ -111,7 +122,7 @@ class forgotpassword implements Interfaces\Api, Interfaces\ApiIgnorePam
break;
default:
$response = array('status'=>'error', 'message'=>'Unknown endpoint');
$response = ['status'=>'error', 'message'=>'Unknown endpoint'];
}
return Factory::response($response);
......
......@@ -56,16 +56,16 @@ class geolocation implements Interfaces\Api, Interfaces\ApiIgnorePam
switch ($pages[0]) {
case 'list':
return Factory::response(array('results'=>$results));
return Factory::response(['results'=>$results]);
break;
default:
$city = isset($data[0]['address']['city']) ? $data[0]['address']['city'] : $data[0]['address']['town'];
$coorinates = $data[0]['lat'] . ',' . $data[0]['lon'];
return Factory::response(array(
return Factory::response([
'city' => $city,
'coordinates' => $coorinates
));
]);
}
}
......
......@@ -46,6 +46,8 @@ class groups implements Interfaces\Api
$response['load-next'] = (string) key($guids);
break;
case "member":
Factory::isLoggedIn();
$manager = new Membership();
$guids = $manager->getGroupsByMember([
'user_guid' => $user->guid,
......
......@@ -59,7 +59,7 @@ class group implements Interfaces\Api
}
$response['group'] = array_filter($response['group'], function ($key) use ($allowed) {
return in_array($key, $allowed);
return in_array($key, $allowed, true);
}, ARRAY_FILTER_USE_KEY);
}
......@@ -184,6 +184,10 @@ class group implements Interfaces\Api
$group->setVideoChatDisabled($_POST['videoChatDisabled']);
}
if (isset($_POST['conversationDisabled'])) {
$group->setConversationDisabled($_POST['conversationDisabled']);
}
if (isset($_POST['tags'])) {
$tags = $_POST['tags'];
$sanitized_tags = [];
......@@ -234,7 +238,7 @@ class group implements Interfaces\Api
}
}
$response = array();
$response = [];
$response['guid'] = $group->getGuid();
if ($creation && isset($_POST['invitees']) && $_POST['invitees']) {
......@@ -257,7 +261,7 @@ class group implements Interfaces\Api
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
......@@ -271,11 +275,7 @@ class group implements Interfaces\Api
return Factory::response([]);
}
$canDelete = Session::isAdmin();
if (!$canDelete && $group->isCreator($user)) {
$canDelete = $group->getMembersCount() <= 1;
}
$canDelete = Session::isAdmin() || $group->isCreator($user);
if (!$canDelete) {
return Factory::response([
......@@ -298,10 +298,11 @@ class group implements Interfaces\Api
/**
* Uploads a Group avatar
* @param GroupEntity $group
* @param GroupEntity $group
* @return GroupEntity
* @throws \IOException
* @throws \InvalidParameterException
* @throws \ImagickException
*/
protected function uploadAvatar(GroupEntity $group)
{
......@@ -309,13 +310,18 @@ class group implements Interfaces\Api
$group_owner = EntitiesFactory::build($group->getOwnerObj());
foreach (['tiny', 'small', 'medium', 'large'] as $size) {
$resized = get_resized_image_from_uploaded_file('file', $icon_sizes[$size]['w'], $icon_sizes[$size]['h'], $icon_sizes[$size]['square']);
/** @var Core\Media\Imagick\Manager $manager */
$manager = Core\Di\Di::_()->get('Media\Imagick\Manager');
$manager->setImage($_FILES['file']['tmp_name'])
->autorotate()
->resize($icon_sizes[$size]['w'], $icon_sizes[$size]['h'], true, $icon_sizes[$size]['square']);
$file = new FileEntity();
$file->owner_guid = $group->owner_guid ?: $group_owner->getGuid();
$file->setFilename("groups/{$group->getGuid()}{$size}.jpg");
$file->open('write');
$file->write($resized);
$file->write($manager->getJpeg());
$file->close();
}
......@@ -327,27 +333,34 @@ class group implements Interfaces\Api
/**
* Uploads a Group banner
* @param GroupEntity $group
* @param GroupEntity $group
* @param $banner_position
* @return GroupEntity
* @throws \IOException
* @throws \InvalidParameterException
* @throws \ImagickException
*/
protected function uploadBanner($group, $banner_position)
{
$group_owner = EntitiesFactory::build($group->getOwnerObj());
$resized = get_resized_image_from_uploaded_file('file', 3840, 1404);
/** @var Core\Media\Imagick\Manager $manager */
$manager = Core\Di\Di::_()->get('Media\Imagick\Manager');
$manager->setImage($_FILES['file']['tmp_name'])
->autorotate()
->resize(3840, 1404);
$file = new FileEntity();
$file->owner_guid = $group->owner_guid ?: $group_owner->getGuid();
$file->setFilename("group/{$group->getGuid()}.jpg");
$file->open('write');
$file->write($resized);
$file->write($manager->getJpeg());
$file->close();
$group
->setBanner(time())
->setBannerPosition($banner_position);
->setBanner(time())
->setBannerPosition($banner_position);
$group->save();
......
......@@ -102,7 +102,7 @@ class membership implements Interfaces\Api
}
$suggestions = (new Documents())->suggestQuery($_GET['q'], [ 'size' => 100 ]);
$guids = array_map(function($row) {
$guids = array_map(function ($row) {
return $row['_source']['guid'];
}, $suggestions['suggest']['autocomplete'][0]['options']);
......@@ -115,7 +115,7 @@ class membership implements Interfaces\Api
}
$i = 0;
$guids = array_filter($guids, function($guid) use ($membership, &$i) {
$guids = array_filter($guids, function ($guid) use ($membership, &$i) {
if ($is > 12) {
return false;
}
......
......@@ -19,6 +19,13 @@ class review implements Interfaces\Api
$group = Entities\Factory::build($pages[0]);
$user = Core\Session::getLoggedInUser();
if (!$group) {
return Factory::response([
'status' => 'error',
'message' => 'Group not found'
]);
}
if (!$group->isOwner($user) && !$group->isModerator($user)) {
return Factory::response([
'status' => 'error',
......
......@@ -14,7 +14,6 @@ use Minds\Api\Factory;
class guid implements Interfaces\Api
{
/**
* Equivalent to HTTP GET method
* @param array $pages
......
......@@ -35,23 +35,24 @@ class header implements Interfaces\Api, Interfaces\ApiIgnorePam
try {
echo $header->read();
} catch (\Exception $e) { }
} catch (\Exception $e) {
}
exit;
}
public function post($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function put($pages)
{
return Factory::response(array());
return Factory::response([]);
}
public function delete($pages)
{
return Factory::response(array());
return Factory::response([]);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.