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
271
Merge Requests
30
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
3230977a
Commit
3230977a
authored
19 hours ago
by
Emiliano Balbuena
Browse files
Options
Download
(wip): Feeds neighbor endpoint
parent
49e337f3
goal/modal-pager
1 merge request
!433
WIP: Modal Page (+ FeedCollection)
Pipeline
#106236153
failed with stages
in 6 minutes and 32 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
351 additions
and
82 deletions
+351
-82
Controllers/api/v2/feeds/neighbor.php
0 → 100644
View file @
3230977a
<?php
/**
* neighbor
*
* @author edgebal
*/
namespace
Minds\Controllers\api\v2\feeds
;
use
Exception
;
use
Minds\Api\Factory
;
use
Minds\Core\Di\Di
;
use
Minds\Core\Feeds\FeedCollection
;
use
Minds\Core\Session
;
use
Minds\Helpers\Text
;
use
Minds\Interfaces
;
class
neighbor
implements
Interfaces\Api
{
/**
* @inheritDoc
*/
public
function
get
(
$pages
)
{
$actor
=
Session
::
getLoggedinUser
()
?:
null
;
/** @var FeedCollection $feedCollection */
$feedCollection
=
Di
::
_
()
->
get
(
'Feeds\Collection'
);
$feedCollection
->
setActor
(
$actor
);
try
{
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
;
default
:
$type
=
$pages
[
2
]
??
''
;
}
$hashtags
=
null
;
if
(
$_GET
[
'hashtag'
]
??
null
)
{
$hashtags
=
Text
::
buildArray
(
$_GET
[
'hashtag'
]);
}
elseif
(
$_GET
[
'hashtags'
]
??
null
)
{
$hashtags
=
Text
::
buildArray
(
explode
(
','
,
$_GET
[
'hashtags'
]));
}
$nsfw
=
array_values
(
array_filter
(
explode
(
','
,
$_GET
[
'nsfw'
]
??
''
)));
//
// TODO: Calculate based on container/owner/subscribed feed
// TODO: Create a class for calculation and use it on other feed endpoints for consistency
$accessIds
=
[
2
];
// TODO: Calculate based on container/owner/subscribed feed
// TODO: Create a class for calculation and use it on other feed endpoints for consistency
$singleOwnerThreshold
=
36
;
//
$feedCollection
->
setFilter
(
$pages
[
0
]
??
''
)
->
setAlgorithm
(
$pages
[
1
]
??
''
)
->
setType
(
$type
)
->
setPeriod
(
$_GET
[
'period'
]
??
'12h'
)
->
setOffset
(
$_GET
[
'offset'
]
??
0
)
->
setCap
(
$actor
->
isAdmin
()
?
5000
:
600
)
->
setAll
((
bool
)
(
$_GET
[
'all'
]
??
false
))
->
setHashtags
(
$hashtags
)
->
setSync
((
bool
)
(
$_GET
[
'sync'
]
??
false
))
->
setPeriodFallback
(
false
)
->
setAsActivities
((
bool
)(
$_GET
[
'as_activities'
]
??
true
))
->
setQuery
(
urldecode
(
$_GET
[
'query'
]
??
''
))
->
setCustomType
(
$_GET
[
'custom_type'
]
??
''
)
->
setContainerGuid
(
$_GET
[
'container_guid'
]
??
null
)
->
setNsfw
(
$nsfw
)
->
setAccessIds
(
$accessIds
)
->
setSingleOwnerThreshold
(
$singleOwnerThreshold
)
->
setLimit
(
1
);
list
(
$prev
,
$next
)
=
$feedCollection
->
fetchAdjacent
(
$_GET
[
'guid'
]
??
null
);
return
Factory
::
response
([
'status'
=>
'success'
,
'prev'
=>
$prev
,
'next'
=>
$next
]);
}
catch
(
Exception
$e
)
{
error_log
((
string
)
$e
);
return
Factory
::
response
([
'status'
=>
'error'
,
'message'
=>
$e
->
getMessage
()
]);
}
}
/**
* @inheritDoc
*/
public
function
post
(
$pages
)
{
return
Factory
::
response
([]);
}
/**
* @inheritDoc
*/
public
function
put
(
$pages
)
{
return
Factory
::
response
([]);
}
/**
* @inheritDoc
*/
public
function
delete
(
$pages
)
{
return
Factory
::
response
([]);
}
}
This diff is collapsed.
Core/EntitiesBuilder.php
View file @
3230977a
...
...
@@ -9,9 +9,9 @@ class EntitiesBuilder
{
/**
* Build by a single guid
* @param $guid
number
* @param $guid
int|string
* @param $opts array
* @return
Entity
* @return
mixed
*/
public
function
single
(
$guid
,
$opts
=
[])
{
...
...
This diff is collapsed.
Core/Feeds/Elastic/Manager.php
View file @
3230977a
...
...
@@ -89,6 +89,7 @@ class Manager
'type'
=>
null
,
'sync'
=>
false
,
'from_timestamp'
=>
null
,
'from_id'
=>
null
,
'query'
=>
null
,
'nsfw'
=>
null
,
'single_owner_threshold'
=>
36
,
...
...
@@ -96,6 +97,7 @@ class Manager
'pinned_guids'
=>
null
,
'as_activities'
=>
false
,
'exclude'
=>
null
,
'reverse'
=>
false
,
],
$opts
);
if
(
isset
(
$opts
[
'query'
])
&&
$opts
[
'query'
])
{
...
...
This diff is collapsed.
Core/Feeds/Elastic/Repository.php
View file @
3230977a
...
...
@@ -66,11 +66,13 @@ class Repository
'query'
=>
null
,
'nsfw'
=>
null
,
'from_timestamp'
=>
null
,
'from_id'
=>
null
,
'exclude_moderated'
=>
false
,
'moderation_reservations'
=>
null
,
'pinned_guids'
=>
null
,
'future'
=>
false
,
'exclude'
=>
null
,
'reverse'
=>
false
,
],
$opts
);
if
(
!
$opts
[
'type'
])
{
...
...
@@ -370,6 +372,12 @@ class Repository
//
if
(
$opts
[
'from_id'
])
{
// TODO: Return results based on 'from_id' and 'reverse' order if necessary
}
//
$esQuery
=
$algorithm
->
getQuery
();
if
(
$esQuery
)
{
$body
[
'query'
][
'function_score'
][
'query'
]
=
array_merge_recursive
(
$body
[
'query'
][
'function_score'
][
'query'
],
$esQuery
);
...
...
This diff is collapsed.
Core/Feeds/Exceptions/OverflowException.php
0 → 100644
View file @
3230977a
<?php
/**
* OverflowException
*
* @author edgebal
*/
namespace
Minds\Core\Feeds\Exceptions
;
use
Exception
;
class
OverflowException
extends
Exception
{
}
This diff is collapsed.
Core/Feeds/FeedCollection.php
View file @
3230977a
...
...
@@ -13,7 +13,9 @@ use Minds\Core\Di\Di;
use
Minds\Core\EntitiesBuilder
;
use
Minds\Core\Feeds\Elastic\Entities
as
ElasticEntities
;
use
Minds\Core\Feeds\Elastic\Manager
as
ElasticManager
;
use
Minds\Core\Feeds\Exceptions\OverflowException
;
use
Minds\Core\Hashtags\User\Manager
as
UserHashtagsManager
;
use
Minds\Core\Security\ACL
;
use
Minds\Entities\User
;
class
FeedCollection
...
...
@@ -116,6 +118,9 @@ class FeedCollection
/** @var EntitiesBuilder */
protected
$entitiesBuilder
;
/** @var ACL */
protected
$acl
;
/** @var Clock */
protected
$clock
;
...
...
@@ -125,6 +130,7 @@ class FeedCollection
* @param ElasticEntities $elasticEntities
* @param UserHashtagsManager $userHashtagsManager
* @param EntitiesBuilder $entitiesBuilder
* @param ACL $acl
* @param Clock $clock
*/
public
function
__construct
(
...
...
@@ -132,12 +138,14 @@ class FeedCollection
$elasticEntities
=
null
,
$userHashtagsManager
=
null
,
$entitiesBuilder
=
null
,
$acl
=
null
,
$clock
=
null
)
{
$this
->
elasticManager
=
$elasticManager
?:
Di
::
_
()
->
get
(
'Feeds\Elastic\Manager'
);
$this
->
elasticEntities
=
$elasticEntities
?:
new
ElasticEntities
();
$this
->
userHashtagsManager
=
$userHashtagsManager
?:
Di
::
_
()
->
get
(
'Hashtags\User\Manager'
);
$this
->
entitiesBuilder
=
$entitiesBuilder
?:
Di
::
_
()
->
get
(
'EntitiesBuilder'
);
$this
->
acl
=
$acl
?:
ACL
::
_
();
$this
->
clock
=
$clock
?:
new
Clock
();
}
...
...
@@ -335,6 +343,115 @@ class FeedCollection
* @throws Exception
*/
public
function
fetch
()
{
try
{
$parameters
=
$this
->
buildParameters
();
}
catch
(
OverflowException
$e
)
{
$emptyResponse
=
new
Response
([]);
$emptyResponse
->
setPagingToken
((
string
)
$this
->
cap
)
->
setLastPage
(
true
)
->
setAttribute
(
'overflow'
,
true
);
return
$emptyResponse
;
}
$opts
=
$parameters
->
getOpts
();
$softLimit
=
$parameters
->
getSoftLimit
();
$response
=
new
Response
();
$fallbackAt
=
null
;
$i
=
0
;
while
(
$response
->
count
()
<
$softLimit
)
{
$result
=
$this
->
elasticManager
->
getList
(
$opts
);
$response
=
$response
->
pushArray
(
$result
->
toArray
());
if
(
!
$this
->
periodFallback
||
!
in_array
(
$this
->
algorithm
,
static
::
ALLOWED_TO_FALLBACK
,
true
)
||
!
isset
(
static
::
PERIOD_FALLBACK
[
$opts
[
'period'
]])
||
++
$i
>
2
// Stop at 2nd fallback (i.e. 12h > 7d > 30d)
)
{
break
;
}
$period
=
$opts
[
'period'
];
$from
=
$this
->
clock
->
now
()
-
static
::
PERIODS
[
$period
];
$opts
[
'from_timestamp'
]
=
$from
*
1000
;
$opts
[
'period'
]
=
static
::
PERIOD_FALLBACK
[
$period
];
if
(
!
$fallbackAt
)
{
$fallbackAt
=
$from
;
}
}
if
(
!
$this
->
sync
)
{
$this
->
elasticEntities
->
setActor
(
$this
->
actor
);
$response
=
$response
->
filter
([
$this
->
elasticEntities
,
'filter'
]);
if
(
$this
->
asActivities
)
{
$response
=
$response
->
map
([
$this
->
elasticEntities
,
'cast'
]);
}
}
$pagingToken
=
$this
->
limit
+
$this
->
offset
;
$response
->
setPagingToken
((
string
)
$pagingToken
)
->
setAttribute
(
'fallbackAt'
,
$fallbackAt
);
return
$response
;
}
/**
* @param string|null $documentId
* @return array
* @throws Exception
*/
public
function
fetchAdjacent
(
?
string
$documentId
)
:
array
{
if
(
!
$documentId
)
{
throw
new
Exception
(
'Invalid document ID'
);
}
$opts
=
$this
->
buildParameters
([
'sync'
=>
true
,
'limit'
=>
1
,
'from_id'
=>
$documentId
,
'reverse'
=>
true
,
])
->
getOpts
();
$prev
=
$this
->
elasticManager
->
getList
(
$opts
)
->
toArray
()[
0
]
??
null
;
$opts
=
$this
->
buildParameters
([
'sync'
=>
true
,
'limit'
=>
1
,
'from_id'
=>
$documentId
])
->
getOpts
();
$next
=
$this
->
elasticManager
->
getList
(
$opts
)
->
toArray
()[
0
]
??
null
;
return
[
$prev
,
$next
];
}
/**
* @param array $optsOverride
* @return FeedCollectionParameters
* @throws OverflowException
* @throws Exception
*/
protected
function
buildParameters
(
array
$optsOverride
=
[])
:
FeedCollectionParameters
{
if
(
!
$this
->
filter
)
{
throw
new
Exception
(
'Missing filter'
);
...
...
@@ -377,13 +494,7 @@ class FeedCollection
}
if
(
$limit
<
0
)
{
$emptyResponse
=
new
Response
([]);
$emptyResponse
->
setPagingToken
((
string
)
$this
->
cap
)
->
setLastPage
(
true
)
->
setAttribute
(
'overflow'
,
true
);
return
$emptyResponse
;
throw
new
OverflowException
();
}
}
...
...
@@ -417,77 +528,30 @@ class FeedCollection
}
}
// Build options
$opts
=
[
'cache_key'
=>
$this
->
actor
?
(
string
)
$this
->
actor
->
guid
:
null
,
'container_guid'
=>
$this
->
containerGuid
,
'access_id'
=>
$this
->
accessIds
,
'custom_type'
=>
$this
->
customType
,
'limit'
=>
$this
->
limit
,
'offset'
=>
$this
->
offset
,
'type'
=>
$this
->
type
,
'algorithm'
=>
$this
->
algorithm
,
'period'
=>
$period
,
'sync'
=>
$this
->
sync
,
'query'
=>
$this
->
query
,
'single_owner_threshold'
=>
$this
->
singleOwnerThreshold
,
'as_activities'
=>
$this
->
asActivities
,
'nsfw'
=>
$this
->
nsfw
,
'hashtags'
=>
$hashtags
,
'filter_hashtags'
=>
$filterHashtags
];
//
$response
=
new
Response
();
$fallbackAt
=
null
;
$i
=
0
;
while
(
$response
->
count
()
<
$limit
)
{
$result
=
$this
->
elasticManager
->
getList
(
$opts
);
$response
=
$response
->
pushArray
(
$result
->
toArray
());
if
(
!
$this
->
periodFallback
||
!
in_array
(
$this
->
algorithm
,
static
::
ALLOWED_TO_FALLBACK
,
true
)
||
!
isset
(
static
::
PERIOD_FALLBACK
[
$opts
[
'period'
]])
||
++
$i
>
2
// Stop at 2nd fallback (i.e. 12h > 7d > 30d)
)
{
break
;
}
$period
=
$opts
[
'period'
];
$from
=
$this
->
clock
->
now
()
-
static
::
PERIODS
[
$period
];
$opts
[
'from_timestamp'
]
=
$from
*
1000
;
$opts
[
'period'
]
=
static
::
PERIOD_FALLBACK
[
$period
];
if
(
!
$fallbackAt
)
{
$fallbackAt
=
$from
;
}
}
if
(
!
$this
->
sync
)
{
$this
->
elasticEntities
->
setActor
(
$this
->
actor
);
$response
=
$response
->
filter
([
$this
->
elasticEntities
,
'filter'
]);
if
(
$this
->
asActivities
)
{
$response
=
$response
->
map
([
$this
->
elasticEntities
,
'cast'
]);
}
}
$pagingToken
=
$this
->
limit
+
$this
->
offset
;
$response
->
setPagingToken
((
string
)
$pagingToken
)
->
setAttribute
(
'fallbackAt'
,
$fallbackAt
);
return
$response
;
// Build parameters
$feedCollectionParameters
=
new
FeedCollectionParameters
();
$feedCollectionParameters
->
setOpts
(
array_merge
([
'cache_key'
=>
$this
->
actor
?
(
string
)
$this
->
actor
->
guid
:
null
,
'container_guid'
=>
$this
->
containerGuid
,
'access_id'
=>
$this
->
accessIds
,
'custom_type'
=>
$this
->
customType
,
'limit'
=>
$this
->
limit
,
'offset'
=>
$this
->
offset
,
'type'
=>
$this
->
type
,
'algorithm'
=>
$this
->
algorithm
,
'period'
=>
$period
,
'sync'
=>
$this
->
sync
,
'query'
=>
$this
->
query
,
'single_owner_threshold'
=>
$this
->
singleOwnerThreshold
,
'as_activities'
=>
$this
->
asActivities
,
'nsfw'
=>
$this
->
nsfw
,
'hashtags'
=>
$hashtags
,
'filter_hashtags'
=>
$filterHashtags
],
$optsOverride
))
->
setSoftLimit
(
$limit
);
return
$feedCollectionParameters
;
}
}
This diff is collapsed.
Core/Feeds/FeedCollectionParameters.php
0 → 100644
View file @
3230977a
<?php
/**
* FeedCollectionParameters
*
* @author edgebal
*/
namespace
Minds\Core\Feeds
;
use
Minds\Traits\MagicAttributes
;
/**
* Class FeedCollectionParameters
* @package Minds\Core\Feeds
* @method array getOpts()
* @method FeedCollectionParameters setOpts(array $opts)
* @method int getSoftLimit()
* @method FeedCollectionParameters setSoftLimit(int $softLimit)
*/
class
FeedCollectionParameters
{
use
MagicAttributes
;
/** @var array */
protected
$opts
;
/** @var int */
protected
$softLimit
;
}
This diff is collapsed.
Core/Feeds/FeedsProvider.php
View file @
3230977a
...
...
@@ -8,7 +8,7 @@ class FeedsProvider extends Provider
{
public
function
register
()
{
$this
->
di
->
bind
(
'Feeds\
Feed
Collection'
,
function
(
$di
)
{
$this
->
di
->
bind
(
'Feeds\Collection'
,
function
(
$di
)
{
return
new
FeedCollection
();
},
[
'useFactory'
=>
true
]);
...
...
This diff is collapsed.
Spec/Core/Feeds/FeedCollectionSpec.php
View file @
3230977a
...
...
@@ -11,6 +11,7 @@ use Minds\Core\Feeds\Elastic\Manager as ElasticManager;
use
Minds\Core\Feeds\FeedCollection
;
use
Minds\Core\Feeds\FeedSyncEntity
;
use
Minds\Core\Hashtags\User\Manager
as
UserHashtagsManager
;
use
Minds\Core\Security\ACL
;
use
Minds\Entities\Entity
;
use
Minds\Entities\User
;
use
PhpSpec\Exception\Example\FailureException
;
...
...
@@ -31,6 +32,9 @@ class FeedCollectionSpec extends ObjectBehavior
/** @var EntitiesBuilder */
protected
$entitiesBuilder
;
/** @var ACL */
protected
$acl
;
/** @var Clock */
protected
$clock
;
...
...
@@ -39,12 +43,14 @@ class FeedCollectionSpec extends ObjectBehavior
ElasticEntities
$elasticEntities
,
UserHashtagsManager
$userHashtagsManager
,
EntitiesBuilder
$entitiesBuilder
,
ACL
$acl
,
Clock
$clock
)
{
$this
->
elasticManager
=
$elasticManager
;
$this
->
elasticEntities
=
$elasticEntities
;
$this
->
userHashtagsManager
=
$userHashtagsManager
;
$this
->
entitiesBuilder
=
$entitiesBuilder
;
$this
->
acl
=
$acl
;
$this
->
clock
=
$clock
;
$this
->
beConstructedWith
(
...
...
@@ -52,6 +58,7 @@ class FeedCollectionSpec extends ObjectBehavior
$elasticEntities
,
$userHashtagsManager
,
$entitiesBuilder
,
$acl
,
$clock
);
}
...
...
This diff is collapsed.
Please
register
or
sign in
to comment