Skip to content
Projects
Groups
Snippets
Help
Sign in / Register
Toggle navigation
Minds Backend - Engine
Project overview
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
283
Merge Requests
37
CI / CD
Security & Compliance
Packages
Wiki
Snippets
Members
Collapse sidebar
Close sidebar
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Minds
Minds Backend - Engine
Commits
2dcc1b00
Commit
2dcc1b00
authored
2 hours ago
by
Emiliano Balbuena
Browse files
Options
Download
(wip): Feed endpoint redux
parent
6a88c337
chore/feed-endpoints
No related merge requests found
Pipeline
#101806358
failed with stages
in 2 minutes and 56 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
559 additions
and
76 deletions
+559
-76
Common/Repository/Response.php
View file @
2dcc1b00
...
...
@@ -24,7 +24,10 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
/** @var bool */
protected
$lastPage
=
false
;
public
function
__construct
(
array
$data
=
null
,
$pagingToken
=
null
)
/** @var array */
protected
$attributes
=
[];
public
function
__construct
(
array
$data
=
null
,
$pagingToken
=
null
,
array
$attributes
=
[])
{
if
(
$data
!==
null
)
{
$this
->
data
=
$data
;
...
...
@@ -33,6 +36,10 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
if
(
$pagingToken
!==
null
)
{
$this
->
pagingToken
=
$pagingToken
;
}
if
(
$this
->
attributes
)
{
$this
->
attributes
=
[];
}
}
/**
...
...
@@ -96,7 +103,7 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
}
/**
* Returns if the result set is fauly
* Returns if the result set is faul
t
y
* @return bool
*/
public
function
hasFailed
()
...
...
@@ -104,6 +111,44 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
return
!!
$this
->
exception
;
}
/**
* @param array $attributes
* @return Response
*/
public
function
setAttributes
(
array
$attributes
)
{
$this
->
attributes
=
$attributes
;
return
$this
;
}
/**
* @return array
*/
public
function
getAttributes
()
{
return
$this
->
attributes
;
}
/**
* @param string $key
* @param mixed $value
* @return Response
*/
public
function
setAttribute
(
string
$key
,
$value
)
{
$this
->
attributes
[
$key
]
=
$value
;
return
$this
;
}
/**
* @param string $key
* @return mixed|null
*/
public
function
getAttribute
(
string
$key
)
{
return
$this
->
attributes
[
$key
]
??
null
;
}
/**
* Return the current element
* @link http://php.net/manual/en/iterator.current.php
...
...
@@ -296,7 +341,7 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
*/
public
function
reverse
(
$preserveKeys
=
false
)
{
return
new
static
(
array_reverse
(
$this
->
data
,
$preserveKeys
),
$this
->
pagingToken
);
return
new
static
(
array_reverse
(
$this
->
data
,
$preserveKeys
),
$this
->
pagingToken
,
$this
->
attributes
);
}
/**
...
...
@@ -315,7 +360,7 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
$filtered
=
array_values
(
$filtered
);
}
return
new
static
(
$filtered
,
$this
->
pagingToken
);
return
new
static
(
$filtered
,
$this
->
pagingToken
,
$this
->
attributes
);
}
/**
...
...
@@ -325,7 +370,7 @@ class Response implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable
*/
public
function
map
(
$callback
)
{
return
new
static
(
array_map
(
$callback
,
$this
->
data
),
$this
->
pagingToken
);
return
new
static
(
array_map
(
$callback
,
$this
->
data
),
$this
->
pagingToken
,
$this
->
attributes
);
}
/**
...
...
This diff is collapsed.
Controllers/api/v2/feeds.php
View file @
2dcc1b00
...
...
@@ -29,104 +29,157 @@ class feeds implements Interfaces\Api
{
Factory
::
isLoggedIn
();
$now
=
time
();
$periodsInSecs
=
Core\Feeds\Elastic\Repository
::
PERIODS
;
/** @var User $currentUser */
$currentUser
=
Core\Session
::
getLoggedinUser
();
$filter
=
$pages
[
0
]
??
null
;
if
(
!
$filter
)
{
return
Factory
::
response
([
'status'
=>
'error'
,
'message'
=>
'Invalid filter'
]);
}
/** @var User $actor */
$actor
=
Core\Session
::
getLoggedinUser
();
$algorithm
=
$pages
[
1
]
??
null
;
if
(
!
$algorithm
)
{
return
Factory
::
response
([
'status'
=>
'error'
,
'message'
=>
'Invalid algorithm'
]);
}
$type
=
''
;
switch
(
$pages
[
2
])
{
switch
(
$pages
[
2
]
??
''
)
{
case
'activities'
:
$type
=
'activity'
;
break
;
case
'channels'
:
$type
=
'user'
;
break
;
case
'images'
:
$type
=
'object:image'
;
break
;
case
'videos'
:
$type
=
'object:video'
;
break
;
case
'groups'
:
$type
=
'group'
;
break
;
case
'blogs'
:
$type
=
'object:blog'
;
break
;
}
$period
=
$_GET
[
'period'
]
??
'12h'
;
if
(
$algorithm
===
'hot'
)
{
$period
=
'12h'
;
}
elseif
(
$algorithm
===
'latest'
)
{
$period
=
'1y'
;
}
//
$hardLimit
=
600
;
if
(
$currentUser
&&
$currentUser
->
isAdmin
())
{
$hardLimit
=
5000
;
default
:
$type
=
$pages
[
2
]
??
''
;
}
$
offset
=
0
;
$
limit
=
(
$_GET
[
'limit'
]
??
0
)
?:
12
;
if
(
isset
(
$_GET
[
'offset'
]))
{
$offset
=
intval
(
$_GET
[
'offset'
]);
}
$hashtags
=
$limit
=
12
;
$feedCollection
=
new
Core\Feeds\FeedCollection
();
$feedCollection
->
setActor
(
$actor
)
->
setFilter
(
$pages
[
0
]
??
''
)
->
setAlgorithm
(
$pages
[
1
]
??
''
)
->
setType
(
$type
)
->
setPeriod
(
$_GET
[
'period'
]
??
'12h'
)
->
setLimit
(
$limit
)
->
setOffset
(
$_GET
[
'offset'
]
??
0
)
->
setCap
(
$actor
->
isAdmin
()
?
5000
:
600
)
->
setAll
((
bool
)
$_GET
[
'all'
]
??
false
)
->
setHashtags
(
$hashtags
)
;
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
,
]);
}
//
$hashtag
=
null
;
if
(
isset
(
$_GET
[
'hashtag'
]))
{
$hashtag
=
strtolower
(
$_GET
[
'hashtag'
]);
}
$now
=
time
();
$periodsInSecs
=
Core\Feeds\Elastic\Repository
::
PERIODS
;
$all
=
false
;
if
(
!
$hashtag
&&
isset
(
$_GET
[
'all'
])
&&
$_GET
[
'all'
])
{
$all
=
true
;
}
// /** @var User $currentUser */
// $currentUser = Core\Session::getLoggedinUser();
// $filter = $pages[0] ?? null;
//
// if (!$filter) {
// return Factory::response([
// 'status' => 'error',
// 'message' => 'Invalid filter'
// ]);
// }
// $algorithm = $pages[1] ?? null;
// if (!$algorithm) {
// return Factory::response([
// 'status' => 'error',
// 'message' => 'Invalid algorithm'
// ]);
// }
// $type = '';
//
// switch ($pages[2]) {
// case 'activities':
// $type = 'activity';
// break;
// case 'channels':
// $type = 'user';
// break;
// case 'images':
// $type = 'object:image';
// break;
// case 'videos':
// $type = 'object:video';
// break;
// case 'groups':
// $type = 'group';
// break;
// case 'blogs':
// $type = 'object:blog';
// break;
// }
// $period = $_GET['period'] ?? '12h';
//
// if ($algorithm === 'hot') {
// $period = '12h';
// } elseif ($algorithm === 'latest') {
// $period = '1y';
// }
// //
//
// $hardLimit = 600;
//
// if ($currentUser && $currentUser->isAdmin()) {
// $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,
// ]);
// }
// //
//
// $hashtag = null;
// if (isset($_GET['hashtag'])) {
// $hashtag = strtolower($_GET['hashtag']);
// }
//
// $all = false;
// if (!$hashtag && isset($_GET['all']) && $_GET['all']) {
// $all = true;
// }
$sync
=
(
bool
)
(
$_GET
[
'sync'
]
??
false
);
...
...
This diff is collapsed.
Core/Feeds/FeedCollection.php
0 → 100644
View file @
2dcc1b00
<?php
/**
* FeedCollection.
*
* @author edgebal
*/
namespace
Minds\Core\Feeds
;
use
Exception
;
use
Minds\Common\Repository\Response
;
use
Minds\Entities\User
;
class
FeedCollection
{
/** @var User|null */
protected
$actor
=
null
;
/** @var string */
protected
$filter
;
/** @var string */
protected
$algorithm
;
/** @var string */
protected
$type
;
/** @var string */
protected
$period
;
/** @var int */
protected
$limit
=
12
;
/** @var int */
protected
$offset
=
0
;
/** @var int */
protected
$cap
=
600
;
/** @var bool */
protected
$all
=
true
;
/** @var array|null */
protected
$hashtags
=
null
;
/**
* @param User|null $actor
* @return FeedCollection
*/
public
function
setActor
(
?
User
$actor
)
:
FeedCollection
{
$this
->
actor
=
$actor
;
return
$this
;
}
/**
* @param string $filter
* @return FeedCollection
*/
public
function
setFilter
(
string
$filter
)
:
FeedCollection
{
$this
->
filter
=
$filter
;
return
$this
;
}
/**
* @param string $algorithm
* @return FeedCollection
*/
public
function
setAlgorithm
(
string
$algorithm
)
:
FeedCollection
{
$this
->
algorithm
=
$algorithm
;
return
$this
;
}
/**
* @param string $type
* @return FeedCollection
*/
public
function
setType
(
string
$type
)
:
FeedCollection
{
$this
->
type
=
$type
;
return
$this
;
}
/**
* @param string $period
* @return FeedCollection
*/
public
function
setPeriod
(
string
$period
)
:
FeedCollection
{
$this
->
period
=
$period
;
return
$this
;
}
/**
* @param int $limit
* @return FeedCollection
*/
public
function
setLimit
(
int
$limit
)
:
FeedCollection
{
$this
->
limit
=
$limit
;
return
$this
;
}
/**
* @param int $offset
* @return FeedCollection
*/
public
function
setOffset
(
int
$offset
)
:
FeedCollection
{
$this
->
offset
=
$offset
;
return
$this
;
}
/**
* @param int $cap
* @return FeedCollection
*/
public
function
setCap
(
int
$cap
)
:
FeedCollection
{
$this
->
cap
=
$cap
;
return
$this
;
}
/**
* @param bool $all
* @return FeedCollection
*/
public
function
setAll
(
bool
$all
)
:
FeedCollection
{
$this
->
all
=
$all
;
return
$this
;
}
/**
* @param array|null $hashtags
* @return FeedCollection
*/
public
function
setHashtags
(
?
array
$hashtags
)
:
FeedCollection
{
$this
->
hashtags
=
$hashtags
;
return
$this
;
}
/**
* @throws Exception
*/
public
function
fetch
()
{
if
(
!
$this
->
filter
)
{
throw
new
Exception
(
'Missing filter'
);
}
if
(
!
$this
->
algorithm
/* TODO: Validate */
)
{
throw
new
Exception
(
'Missing algorithm'
);
}
if
(
!
$this
->
type
/* TODO: Validate */
)
{
throw
new
Exception
(
'Missing type'
);
}
if
(
!
$this
->
period
/* TODO: Validate */
)
{
throw
new
Exception
(
'Missing period'
);
}
$offset
=
abs
(
intval
(
$this
->
offset
?:
0
));
$limit
=
abs
(
intval
(
$this
->
limit
?:
0
));
if
(
$limit
)
{
if
(
$this
->
cap
&&
(
$offset
+
$limit
)
>
$this
->
cap
)
{
$limit
=
$this
->
cap
-
$offset
;
}
if
(
$limit
<
0
)
{
$emptyResponse
=
new
Response
([]);
$emptyResponse
->
setPagingToken
((
string
)
$this
->
cap
)
->
setLastPage
(
true
)
->
setAttribute
(
'overflow'
,
true
);
return
$emptyResponse
;
}
}
$all
=
!
$this
->
hashtags
&&
$this
->
all
;
$response
=
new
Response
();
return
$response
;
}
}
This diff is collapsed.
Spec/Core/Feeds/FeedCollectionSpec.php
0 → 100644
View file @
2dcc1b00
<?php
namespace
Spec\Minds\Core\Feeds
;
use
Exception
;
use
Minds\Common\Repository\Response
;
use
Minds\Core\Feeds\FeedCollection
;
use
Minds\Entities\User
;
use
PhpSpec\Exception\Example\FailureException
;
use
PhpSpec\ObjectBehavior
;
use
Prophecy\Argument
;
class
FeedCollectionSpec
extends
ObjectBehavior
{
public
function
it_is_initializable
()
{
$this
->
shouldHaveType
(
FeedCollection
::
class
);
}
public
function
it_should_fetch
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
fetch
()
->
shouldBeAResponse
([]);
}
public
function
it_should_fetch_with_acl_restrictions
(
User
$actor
)
{
/** @var FeedCollection $this */
$this
->
setActor
(
$actor
)
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
fetch
()
->
shouldBeAResponse
([]);
}
public
function
it_should_fetch_using_offset_limit_and_cap
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
setLimit
(
2
)
->
setOffset
(
0
)
->
setCap
(
3
)
->
fetch
()
->
shouldBeAResponse
([]);
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
setLimit
(
2
)
->
setOffset
(
2
)
->
setCap
(
3
)
->
fetch
()
->
shouldBeAResponse
([]);
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
setLimit
(
2
)
->
setOffset
(
4
)
->
setCap
(
3
)
->
fetch
()
->
shouldBeAResponse
([],
[
'overflow'
=>
true
]);
}
public
function
it_should_fetch_all_or_filtering_by_hashtag
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
setAll
(
true
)
->
setHashtag
(
''
)
->
fetch
()
->
shouldBeAResponse
([]);
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
setAll
(
false
)
->
setHashtag
(
'phpspec'
)
->
fetch
()
->
shouldBeAResponse
([]);
}
public
function
it_should_fetch_filtering_by_preferred_hashtags
(
User
$user
)
{
/** @var FeedCollection $this */
$this
->
setActor
(
$user
)
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
fetch
()
->
shouldBeAResponse
([]);
}
public
function
it_should_throw_if_no_filter_during_fetch
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
''
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
shouldThrow
(
new
Exception
(
'Missing filter'
))
->
duringFetch
();
}
public
function
it_should_throw_if_no_algorithm_during_fetch
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
''
)
->
setType
(
'activity'
)
->
setPeriod
(
'12h'
)
->
shouldThrow
(
new
Exception
(
'Missing algorithm'
))
->
duringFetch
();
}
public
function
it_should_throw_if_no_type_during_fetch
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
''
)
->
setPeriod
(
'12h'
)
->
shouldThrow
(
new
Exception
(
'Missing type'
))
->
duringFetch
();
}
public
function
it_should_throw_if_no_period_during_fetch
()
{
/** @var FeedCollection $this */
$this
->
setFilter
(
'global'
)
->
setAlgorithm
(
'top'
)
->
setType
(
'activity'
)
->
setPeriod
(
''
)
->
shouldThrow
(
new
Exception
(
'Missing period'
))
->
duringFetch
();
}
public
function
getMatchers
()
:
array
{
$matchers
=
[];
$matchers
[
'beAResponse'
]
=
function
(
$subject
,
$elements
=
null
,
$attributes
=
null
)
{
if
(
!
(
$subject
instanceof
Response
))
{
throw
new
FailureException
(
"Subject should be a Response"
);
}
if
(
$elements
!==
null
&&
$elements
!==
$subject
->
toArray
())
{
throw
new
FailureException
(
"Subject elements don't match"
);
}
if
(
$attributes
!==
null
&&
$attributes
!==
$subject
->
getAttributes
())
{
throw
new
FailureException
(
"Subject attributes don't match"
);
}
return
true
;
};
return
$matchers
;
}
}
This diff is collapsed.
Please
register
or
sign in
to comment