Skip to content
Commits on Source (64)
......@@ -9,6 +9,7 @@ stages:
- prepare
- review
- deploy:staging
- qa
- deploy:canary
- deploy:production
......@@ -22,7 +23,7 @@ build:
stage: build
script:
- apk update && apk add --no-cache git
- sh tools/setup.sh
- sh tools/setup.sh production
cache:
paths:
- vendor
......@@ -127,6 +128,17 @@ review:stop:
- master
- test/gitlab-ci
qa:manual:
stage: qa
script:
- echo "Manually approved"
when: manual
only:
refs:
- master
- test/gitlab-ci
allow_failure: false
staging:fpm:
stage: deploy:staging
image: minds/ci:latest
......
......@@ -2,6 +2,8 @@
namespace Minds\Api;
use Minds\Core\Di\Di;
use Minds\Core\Pro\Domain\Security as ProDomainSecurity;
use Minds\Interfaces;
use Minds\Helpers;
use Minds\Core\Security;
......@@ -32,6 +34,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 +45,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) ?: [];
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) ?: [];
return $handler->$method($pages);
}
--$loop;
}
}
......@@ -78,15 +100,18 @@ 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();
header('Content-type: application/json');
header("Access-Control-Allow-Origin: *");
header('HTTP/1.1 401 Unauthorized', true, 401);
echo json_encode([
'error' => 'Sorry, you are not authenticated',
......@@ -108,8 +133,10 @@ 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(['error'=>'You are not an admin', 'code'=>401]);
exit;
......@@ -126,8 +153,10 @@ class Factory
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',
......@@ -151,11 +180,26 @@ class Factory
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
......
<?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);
}
}
......@@ -328,4 +328,13 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
{
return array_reduce($this->data, $callback, $initialValue);
}
/**
* Returns the first element of the Response, or null if empty
* @return mixed|null
*/
public function first()
{
return $this->data[0] ?? null;
}
}
<?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);
}
}
}
......@@ -50,4 +50,35 @@ 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);
}
}
}
......@@ -16,6 +16,8 @@ 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
{
......@@ -44,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');
......@@ -116,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 {
......
......@@ -141,6 +141,7 @@ class blog implements Interfaces\Api
!$blog ||
Helpers\Flags::shouldFail($blog) ||
!Core\Security\ACL::_()->read($blog)
|| ($blog->getTimeCreated() > time() && !$blog->canEdit())
) {
break;
}
......@@ -245,13 +246,6 @@ class blog implements Interfaces\Api
}
}
if (!$blog->isPublished()) {
$blog->setAccessId(Access::UNLISTED);
$blog->setDraftAccessId($_POST['access_id']);
} elseif ($blog->getTimePublished() == '') {
$blog->setTimePublished(time());
}
$blog->setLastSave(time());
if (isset($_POST['wire_threshold'])) {
......@@ -298,6 +292,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',
......@@ -326,18 +345,24 @@ class blog implements Interfaces\Api
}
if ($saved && is_uploaded_file($_FILES['file']['tmp_name'])) {
/** @var Core\Media\Imagick\Manager $manager */
$manager = Core\Di\Di::_()->get('Media\Imagick\Manager');
$manager->setImage($_FILES['file']['tmp_name'])
->resize(2000, 1000);
try {
$manager->setImage($_FILES['file']['tmp_name'])
->resize(2000, 1000);
$header->write($blog, $manager->getJpeg(), isset($_POST['header_top']) ? (int) $_POST['header_top'] : 0);
$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) {
if ($blog->isPublished() && $blog->getAccessId() == Access::PUBLIC) {
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);
}
......
......@@ -13,6 +13,7 @@ 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
......@@ -46,6 +47,10 @@ class channel implements Interfaces\Api
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([$user]);
......@@ -87,6 +92,19 @@ class channel implements Interfaces\Api
$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);
}
......
......@@ -38,10 +38,10 @@ class media implements Interfaces\Api, Interfaces\ApiIgnorePam
switch ($entity->subtype) {
case "video":
Helpers\Counters::increment($pages[0], 'plays');
// Helpers\Counters::increment($pages[0], 'plays');
if (isset($pages[1]) && $pages[1] == 'play') {
http_response_code(301);
http_response_code(302);
if ($entity->subtype == 'audio') {
\forward($entity->getSourceUrl('128.mp3'));
......
......@@ -13,6 +13,7 @@ use Minds\Helpers;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Core\Features\Manager as FeaturesManager;
class thumbnails implements Interfaces\Api, Interfaces\ApiIgnorePam
{
......@@ -28,6 +29,17 @@ class thumbnails implements Interfaces\Api, Interfaces\ApiIgnorePam
exit;
}
$featuresManager = new FeaturesManager();
if ($featuresManager->has('cdn-jwt')) {
error_log("{$_SERVER['REQUEST_URI']} was hit, and should not have been");
return Factory::response([
'status' => 'error',
'message' => 'This endpoint has been deprecated. Please use fs/v1/thumbnail',
]);
}
$guid = $pages[0];
Core\Security\ACL::$ignore = true;
......
......@@ -514,12 +514,23 @@ class newsfeed implements Interfaces\Api
$activity->indexes = ["activity:$activity->owner_guid:edits"]; //don't re-index on edit
(new Core\Translation\Storage())->purge($activity->guid);
$attachmentPaywallDelegate = new Core\Feeds\Activity\Delegates\AttachmentPaywallDelegate();
$attachmentPaywallDelegate->onUpdate($activity);
if (isset($_POST['time_created']) && ($_POST['time_created'] != $activity->getTimeCreated())) {
try {
$timeCreatedDelegate = new Core\Feeds\Activity\Delegates\TimeCreatedDelegate();
$timeCreatedDelegate->onUpdate($activity, $_POST['time_created'], time());
} catch (\Exception $e) {
return Factory::response([
'status' => 'error',
'message' => $e->getMessage(),
]);
}
}
$save->setEntity($activity)
->save();
(new Core\Entities\PropagateProperties())->from($activity);
$activity->setExportContext(true);
return Factory::response(['guid' => $activity->guid, 'activity' => $activity->export(), 'edited' => true]);
}
......@@ -529,6 +540,19 @@ class newsfeed implements Interfaces\Api
$activity->setMature(isset($_POST['mature']) && !!$_POST['mature']);
$user = Core\Session::getLoggedInUser();
if (isset($_POST['time_created'])) {
try {
$timeCreatedDelegate = new Core\Feeds\Activity\Delegates\TimeCreatedDelegate();
$timeCreatedDelegate->onAdd($activity, $_POST['time_created'], time());
} catch (\Exception $e) {
return Factory::response([
'status' => 'error',
'message' => $e->getMessage(),
]);
}
}
if ($user->isMature()) {
$activity->setMature(true);
}
......@@ -599,6 +623,8 @@ class newsfeed implements Interfaces\Api
$attachment->setNsfw($activity->getNsfw());
$attachment->set('time_created', $activity->getTimeCreated());
$save->setEntity($attachment)->save();
switch ($attachment->subtype) {
......
......@@ -5,14 +5,14 @@
* @version 1
* @author Mark Harding
*/
namespace Minds\Controllers\api\v1;
use Minds\Api\Factory;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Entities;
use Minds\Entities\User;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers;
class register implements Interfaces\Api, Interfaces\ApiIgnorePam
{
......@@ -21,7 +21,7 @@ class register implements Interfaces\Api, Interfaces\ApiIgnorePam
*/
public function get($pages)
{
return Factory::response(['status'=>'error', 'message'=>'GET is not supported for this endpoint']);
return Factory::response(['status' => 'error', 'message' => 'GET is not supported for this endpoint']);
}
/**
......@@ -37,11 +37,11 @@ class register implements Interfaces\Api, Interfaces\ApiIgnorePam
public function post($pages)
{
if (!isset($_POST['username']) || !isset($_POST['password']) || !isset($_POST['username']) || !isset($_POST['email'])) {
return Factory::response(['status'=>'error']);
return Factory::response(['status' => 'error']);
}
if (!$_POST['username'] || !$_POST['password'] || !$_POST['username'] || !$_POST['email']) {
return Factory::response(['status'=>'error', 'message' => "Please fill out all the fields"]);
return Factory::response(['status' => 'error', 'message' => "Please fill out all the fields"]);
}
try {
......@@ -67,14 +67,37 @@ class register implements Interfaces\Api, Interfaces\ApiIgnorePam
]);
}
if (!(isset($_POST['parentId']) || isset($_POST['previousUrl']) || isset($_SERVER['HTTP_APP_VERSION']))) {
return Factory::response(['status'=>'error', 'message' => "Please refresh your browser or update you app. We don't recognise your platform."]);
}
$user = register_user($_POST['username'], $_POST['password'], $_POST['username'], $_POST['email'], false);
$guid = $user->guid;
// Hacky, move to service soon!
$hasSignupTags = false;
if (isset($_COOKIE['mexp'])) {
$manager = Core\Di\Di::_()->get('Experiments\Manager');
$bucket = $manager->getBucketForExperiment('Homepage200619');
$user->expHomepage200619 = $bucket->getId();
}
if (isset($_POST['parentId'])) {
$user->signupParentId = (string) $_POST['parentId'];
$hasSignupTags = true;
}
if (isset($_POST['previousUrl'])) {
$user->signupPreviousUrl = (string) $_POST['previousUrl'];
$hasSignupTags = true;
}
if (isset($_SERVER['HTTP_APP_VERSION'])) {
$user->signupParentId = 'mobile-native';
$hasSignupTags = true;
}
if ($hasSignupTags) {
$user->save();
} else {
return Factory::response(['status'=>'error', 'message' => "Please refresh your browser or update you app. We don't recognise your platform."]);
}
$params = [
......@@ -96,11 +119,11 @@ class register implements Interfaces\Api, Interfaces\ApiIgnorePam
$sessions->save(); // Save to db and cookie
$response = [
'guid' => $guid,
'user' => $user->export()
'guid' => $guid,
'user' => $user->export(),
];
} catch (\Exception $e) {
$response = ['status'=>'error', 'message'=>$e->getMessage()];
$response = ['status' => 'error', 'message' => $e->getMessage()];
}
return Factory::response($response);
}
......
......@@ -69,10 +69,6 @@ class settings implements Interfaces\Api
{
Factory::isLoggedIn();
if (!Core\Security\XSRF::validateRequest()) {
//return false;
}
if (Core\Session::getLoggedInUser()->isAdmin() && isset($pages[0])) {
$user = new entities\User($pages[0]);
} else {
......
<?php
/**
* pro
*
* @author edgebal
*/
namespace Minds\Controllers\api\v2\admin;
use Minds\Api\Factory;
use Minds\Core\Pro\Manager;
use Minds\Entities\User as UserEntity;
use Minds\Interfaces;
use Minds\Core\Di\Di;
class pro implements Interfaces\Api, Interfaces\ApiAdminPam
{
/**
* Equivalent to HTTP GET method
* @param array $pages
* @return mixed|null
*/
public function get($pages)
{
return Factory::response([]);
}
/**
* Equivalent to HTTP POST method
* @param array $pages
* @return mixed|null
*/
public function post($pages)
{
return Factory::response([]);
}
/**
* Equivalent to HTTP PUT method
* @param array $pages
* @return mixed|null
*/
public function put($pages)
{
if (!($pages[0] ?? null)) {
return Factory::response([
'status' => 'error',
'message' => 'Emtpy target',
]);
}
$target = new UserEntity($pages[0]);
if (!$target || !$target->guid) {
return Factory::response([
'status' => 'error',
'message' => 'Invalid target',
]);
}
/** @var Manager $manager */
$manager = Di::_()->get('Pro\Manager');
$manager
->setUser($target);
$success = $manager->enable(time() + (365 * 86400));
if (!$success) {
return Factory::response([
'status' => 'error',
'message' => 'Error disabling Pro',
]);
}
return Factory::response([]);
}
/**
* Equivalent to HTTP DELETE method
* @param array $pages
* @return mixed|null
*/
public function delete($pages)
{
if (!($pages[0] ?? null)) {
return Factory::response([
'status' => 'error',
'message' => 'Emtpy target',
]);
}
$target = new UserEntity($pages[0]);
if (!$target || !$target->guid) {
return Factory::response([
'status' => 'error',
'message' => 'Invalid target',
]);
}
/** @var Manager $manager */
$manager = Di::_()->get('Pro\Manager');
$manager
->setUser($target);
$success = $manager->disable();
if (!$success) {
return Factory::response([
'status' => 'error',
'message' => 'Error disabling Pro',
]);
}
return Factory::response([]);
}
}
......@@ -53,6 +53,7 @@ class views implements Interfaces\Api
$viewsManager->record(
(new Core\Analytics\Views\View())
->setEntityUrn($boost->getEntity()->getUrn())
->setOwnerGuid((string) $boost->getEntity()->getOwnerGuid())
->setClientMeta($_POST['client_meta'] ?? [])
);
} catch (\Exception $e) {
......@@ -66,51 +67,59 @@ class views implements Interfaces\Api
]);
break;
case 'activity':
$activity = new Entities\Activity($pages[1]);
case 'entity':
$entity = Entities\Factory::build($pages[1]);
if (!$activity->guid) {
if (!$entity) {
return Factory::response([
'status' => 'error',
'message' => 'Could not find activity post'
'message' => 'Could not the entity'
]);
}
try {
Core\Analytics\App::_()
if ($entity->type === 'activity') {
try {
Core\Analytics\App::_()
->setMetric('impression')
->setKey($activity->guid)
->setKey($entity->guid)
->increment();
if ($activity->remind_object) {
Core\Analytics\App::_()
if ($entity->remind_object) {
Core\Analytics\App::_()
->setMetric('impression')
->setKey($activity->remind_object['guid'])
->setKey($entity->remind_object['guid'])
->increment();
Core\Analytics\App::_()
Core\Analytics\App::_()
->setMetric('impression')
->setKey($activity->remind_object['owner_guid'])
->setKey($entity->remind_object['owner_guid'])
->increment();
}
}
Core\Analytics\User::_()
Core\Analytics\User::_()
->setMetric('impression')
->setKey($activity->owner_guid)
->setKey($entity->owner_guid)
->increment();
} catch (\Exception $e) {
error_log($e->getMessage());
} catch (\Exception $e) {
error_log($e->getMessage());
}
}
try {
$viewsManager->record(
(new Core\Analytics\Views\View())
->setEntityUrn($activity->getUrn())
->setEntityUrn($entity->getUrn())
->setOwnerGuid((string) $entity->getOwnerGuid())
->setClientMeta($_POST['client_meta'] ?? [])
);
} catch (\Exception $e) {
error_log($e);
}
Di::_()->get('Referrals\Cookie')
->setEntity($entity)
->create();
break;
}
......
......@@ -124,10 +124,14 @@ class feed implements Interfaces\Api
// $next = 0;
// }
$len = count($boosts);
$next = $boosts[$len -1]->getTimestamp();
if ($boosts[$len -1]) {
$next = $boosts[$len -1]->getTimestamp();
}
} elseif ($isBoostFeed) {
$len = count($boosts);
$next = $boosts[$len -1]->getTimestamp();
if ($boosts[$len -1]) {
$next = $boosts[$len -1]->getTimestamp();
}
}
// $ttl = 1800; // 30 minutes
......
<?php
namespace Minds\Controllers\api\v2\feeds;
use Minds\Api\Exportable;
use Minds\Api\Factory;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Entities\Factory as EntitiesFactory;
use Minds\Entities\User;
use Minds\Interfaces;
class scheduled implements Interfaces\Api
{
/**
* Equivalent to HTTP GET method
* @param array $pages
* @return mixed|null
* @throws \Exception
*/
public function get($pages)
{
/** @var User $currentUser */
$currentUser = Core\Session::getLoggedinUser();
//
$container_guid = $pages[0] ?? null;
if (!$container_guid) {
return Factory::response([
'status' => 'error',
'message' => 'Invalid container',
]);
}
$container = EntitiesFactory::build($container_guid);
if (!$container || !Core\Security\ACL::_()->read($container, $currentUser)) {
return Factory::response([
'status' => 'error',
'message' => 'Forbidden',
]);
}
$type = '';
switch ($pages[1]) {
case 'activities':
$type = 'activity';
break;
case 'images':
$type = 'object:image';
break;
case 'videos':
$type = 'object:video';
break;
case 'blogs':
$type = 'object:blog';
break;
case 'count':
$type = 'activity';
/** @var Core\Feeds\Scheduled\Manager $manager */
$manager = new Core\Feeds\Scheduled\Manager;
return Factory::response([
'status' => 'success',
'count' => $manager->getScheduledCount(['container_guid' => $container_guid, 'type' => $type])
]);
default:
return Factory::response([
'status' => 'error',
'message' => 'Invalid type',
]);
}
$hardLimit = 5000;
$offset = 0;
if (isset($_GET['offset'])) {
$offset = intval($_GET['offset']);
}
$limit = 12;
if (isset($_GET['limit'])) {
$limit = abs(intval($_GET['limit']));
}
if (($offset + $limit) > $hardLimit) {
$limit = $hardLimit - $offset;
}
if ($limit <= 0) {
return Factory::response([
'status' => 'success',
'entities' => [],
'load-next' => $hardLimit,
'overflow' => true,
]);
}
//
$sync = (bool) ($_GET['sync'] ?? false);
$fromTimestamp = $_GET['from_timestamp'] ?? 0;
$asActivities = (bool) ($_GET['as_activities'] ?? true);
$forcePublic = (bool) ($_GET['force_public'] ?? false);
$query = null;
if (isset($_GET['query'])) {
$query = $_GET['query'];
}
$custom_type = isset($_GET['custom_type']) && $_GET['custom_type'] ? [$_GET['custom_type']] : null;
/** @var Core\Feeds\Top\Manager $manager */
$manager = Di::_()->get('Feeds\Top\Manager');
/** @var Core\Feeds\Top\Entities $entities */
$entities = new Core\Feeds\Top\Entities();
$entities->setActor($currentUser);
$isOwner = false;
if ($currentUser) {
$entities->setActor($currentUser);
$isOwner = $currentUser->guid == $container_guid;
}
$opts = [
'cache_key' => $currentUser ? $currentUser->guid : null,
'container_guid' => $container_guid,
'access_id' => $isOwner && !$forcePublic ? [0, 1, 2, $container_guid] : [2, $container_guid],
'custom_type' => $custom_type,
'limit' => $limit,
'type' => $type,
'algorithm' => 'latest',
'period' => '1y',
'sync' => $sync,
'from_timestamp' => $fromTimestamp,
'query' => $query,
'single_owner_threshold' => 0,
'pinned_guids' => $type === 'activity' ? array_reverse($container->getPinnedPosts()) : null,
'time_created_upper' => false,
];
if (isset($_GET['nsfw'])) {
$nsfw = $_GET['nsfw'] ?? '';
$opts['nsfw'] = explode(',', $nsfw);
}
try {
$result = $manager->getList($opts);
if (!$sync) {
// Remove all unlisted content, if ES document is not in sync, it'll
// also remove pending activities
$result = $result->filter([$entities, 'filter']);
if ($asActivities) {
// Cast to ephemeral Activity entities, if another type
$result = $result->map([$entities, 'cast']);
}
}
return Factory::response([
'status' => 'success',
'entities' => Exportable::_($result),
'load-next' => $result->getPagingToken(),
]);
} catch (\Exception $e) {
error_log($e);
return Factory::response(['status' => 'error', 'message' => $e->getMessage()]);
}
}
public function post($pages)
{
return Factory::response([]);
}
public function put($pages)
{
return Factory::response([]);
}
public function delete($pages)
{
return Factory::response([]);
}
}
......@@ -29,6 +29,13 @@ class connect implements Interfaces\Api
]);
}
if (!$account) {
return Factory::response([
'status' => 'error',
'message' => 'Account not found',
]);
}
return Factory::response([
'account' => $account->export(),
]);
......
<?php
/**
* pro
* @author edgebal
*/
namespace Minds\Controllers\api\v2;
use Exception;
use Minds\Core\Di\Di;
use Minds\Core\Pro\Manager;
use Minds\Core\Session;
use Minds\Interfaces;
use Minds\Api\Factory;
class pro implements Interfaces\Api
{
/**
* Equivalent to HTTP GET method
* @param array $pages
* @return mixed|null
* @throws Exception
*/
public function get($pages)
{
/** @var Manager $manager */
$manager = Di::_()->get('Pro\Manager');
$manager
->setUser(Session::getLoggedinUser());
return Factory::response([
'isActive' => $manager->isActive(),
]);
}
/**
* Equivalent to HTTP POST method
* @param array $pages
* @return mixed
*/
public function post($pages)
{
return Factory::response([
'status' => 'error',
'message' => 'Minds Pro is not yet publicly available.',
]);
// /** @var Manager $manager */
// $manager = Di::_()->get('Pro\Manager');
// $manager
// ->setUser(Session::getLoggedinUser());
//
// // TODO: Send and process payment data
// $success = $manager->enable(time() + (365 * 86400));
//
// if (!$success) {
// return Factory::response([
// 'status' => 'error',
// 'message' => 'Error activating Pro',
// ]);
// }
//
// return Factory::response([
// 'isActive' => $manager->isActive(),
// 'settings' => $manager->get(),
// ]);
}
/**
* Equivalent to HTTP PUT method
* @param array $pages
* @return mixed|null
*/
public function put($pages)
{
return Factory::response([]);
}
/**
* Equivalent to HTTP DELETE method
* @param array $pages
* @return mixed
*/
public function delete($pages)
{
/** @var Manager $manager */
$manager = Di::_()->get('Pro\Manager');
$manager
->setUser(Session::getLoggedinUser());
$success = $manager->disable();
if (!$success) {
return Factory::response([
'status' => 'error',
'message' => 'Error disabling Pro',
]);
}
return Factory::response([]);
}
}