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
286
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
ad8aba3d
Commit
ad8aba3d
authored
48 minutes ago
by
Emiliano Balbuena
Browse files
Options
Download
(feat): FeedCollection and /api/v2/feeds
parent
2dcc1b00
chore/feed-endpoints
No related merge requests found
Pipeline
#101852118
failed with stages
in 2 minutes and 53 seconds
Changes
5
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
397 additions
and
262 deletions
+397
-262
Controllers/api/v2/feeds.php
View file @
ad8aba3d
This diff is collapsed.
Click to expand it.
Core/Clock.php
0 → 100644
View file @
ad8aba3d
<?php
/**
* Clock.
*
* @author edgebal
*/
namespace
Minds\Core
;
class
Clock
{
/**
* Returns the current system time
* @return int
*/
public
function
now
()
{
return
time
();
}
}
This diff is collapsed.
Core/Feeds/FeedCollection.php
View file @
ad8aba3d
...
...
@@ -8,10 +8,44 @@ namespace Minds\Core\Feeds;
use
Exception
;
use
Minds\Common\Repository\Response
;
use
Minds\Core\Clock
;
use
Minds\Core\Di\Di
;
use
Minds\Core\Feeds\Elastic\Entities
as
ElasticEntities
;
use
Minds\Core\Feeds\Elastic\Manager
as
ElasticManager
;
use
Minds\Core\Hashtags\User\Manager
as
UserHashtagsManager
;
use
Minds\Entities\User
;
class
FeedCollection
{
/** @var string[] */
const
ALGORITHMS
=
[
'top'
,
'hot'
,
'latest'
];
/** @var array */
const
PERIODS
=
[
'12h'
=>
43200
,
'24h'
=>
86400
,
'7d'
=>
604800
,
'30d'
=>
2592000
,
'1y'
=>
31536000
,
];
/** @var array */
const
PERIOD_FALLBACK
=
[
'12h'
=>
'7d'
,
'24h'
=>
'7d'
,
'7d'
=>
'30d'
,
'30d'
=>
'1y'
];
/** @var string[] */
const
ALLOWED_TO_FALLBACK
=
[
'top'
];
/** @var User|null */
protected
$actor
=
null
;
...
...
@@ -39,9 +73,68 @@ class FeedCollection
/** @var bool */
protected
$all
=
true
;
/** @var
array
|null */
/** @var
string[]
|null */
protected
$hashtags
=
null
;
/** @var bool */
protected
$sync
=
false
;
/** @var bool */
protected
$periodFallback
=
false
;
/** @var bool */
protected
$asActivities
=
false
;
/** @var string */
protected
$query
=
''
;
/** @var string */
protected
$customType
=
''
;
/** @var string|null */
protected
$containerGuid
;
/** @var string[]|null */
protected
$nsfw
=
[];
/** @var int[]|null */
protected
$accessIds
=
null
;
/** @var int */
protected
$singleOwnerThreshold
=
0
;
/** @var ElasticManager */
protected
$elasticManager
;
/** @var ElasticEntities */
protected
$elasticEntities
;
/** @var UserHashtagsManager */
protected
$userHashtagsManager
;
/** @var Clock */
protected
$clock
;
/**
* FeedCollection constructor.
* @param ElasticManager $elasticManager
* @param ElasticEntities $elasticEntities
* @param UserHashtagsManager $userHashtagsManager
* @param Clock $clock
*/
public
function
__construct
(
$elasticManager
=
null
,
$elasticEntities
=
null
,
$userHashtagsManager
=
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
->
clock
=
$clock
?:
new
Clock
();
}
/**
* @param User|null $actor
* @return FeedCollection
...
...
@@ -142,6 +235,96 @@ class FeedCollection
return
$this
;
}
/**
* @param bool $sync
* @return FeedCollection
*/
public
function
setSync
(
bool
$sync
)
:
FeedCollection
{
$this
->
sync
=
$sync
;
return
$this
;
}
/**
* @param bool $periodFallback
* @return FeedCollection
*/
public
function
setPeriodFallback
(
bool
$periodFallback
)
:
FeedCollection
{
$this
->
periodFallback
=
$periodFallback
;
return
$this
;
}
/**
* @param bool $asActivities
* @return FeedCollection
*/
public
function
setAsActivities
(
bool
$asActivities
)
:
FeedCollection
{
$this
->
asActivities
=
$asActivities
;
return
$this
;
}
/**
* @param string $query
* @return FeedCollection
*/
public
function
setQuery
(
string
$query
)
:
FeedCollection
{
$this
->
query
=
$query
;
return
$this
;
}
/**
* @param string $customType
* @return FeedCollection
*/
public
function
setCustomType
(
string
$customType
)
:
FeedCollection
{
$this
->
customType
=
$customType
;
return
$this
;
}
/**
* @param string|null $containerGuid
* @return FeedCollection
*/
public
function
setContainerGuid
(
?
string
$containerGuid
)
:
FeedCollection
{
$this
->
containerGuid
=
$containerGuid
;
return
$this
;
}
/**
* @param string[]|null $nsfw
* @return FeedCollection
*/
public
function
setNsfw
(
?
array
$nsfw
)
:
FeedCollection
{
$this
->
nsfw
=
$nsfw
;
return
$this
;
}
/**
* @param int[]|null $accessIds
* @return FeedCollection
*/
public
function
setAccessIds
(
?
array
$accessIds
)
:
FeedCollection
{
$this
->
accessIds
=
$accessIds
;
return
$this
;
}
/**
* @param int $singleOwnerThreshold
* @return FeedCollection
*/
public
function
setSingleOwnerThreshold
(
int
$singleOwnerThreshold
)
:
FeedCollection
{
$this
->
singleOwnerThreshold
=
$singleOwnerThreshold
;
return
$this
;
}
/**
* @throws Exception
*/
...
...
@@ -163,6 +346,22 @@ class FeedCollection
throw
new
Exception
(
'Missing period'
);
}
// Normalize period
$period
=
$this
->
period
;
switch
(
$this
->
algorithm
)
{
case
'hot'
:
$period
=
'12h'
;
break
;
case
'latest'
:
$period
=
'1y'
;
break
;
}
// Normalize and calculate limit
$offset
=
abs
(
intval
(
$this
->
offset
?:
0
));
$limit
=
abs
(
intval
(
$this
->
limit
?:
0
));
...
...
@@ -182,9 +381,104 @@ class FeedCollection
}
}
// Normalize hashtags
$all
=
!
$this
->
hashtags
&&
$this
->
all
;
$hashtags
=
$this
->
hashtags
;
$filterHashtags
=
true
;
// Fetch preferred hashtags
if
(
!
$all
&&
!
$hashtags
&&
$this
->
actor
)
{
$hashtags
=
$this
->
userHashtagsManager
->
setUser
(
$this
->
actor
)
->
values
([
'limit'
=>
50
,
'trending'
=>
false
,
'defaults'
=>
false
,
]);
$filterHashtags
=
false
;
}
// Check container readability
if
(
$this
->
containerGuid
)
{
$container
=
$this
->
entitiesBuilder
->
single
(
$this
->
containerGuid
);
if
(
!
$container
||
!
$this
->
acl
->
read
(
$container
))
{
throw
new
Exception
(
'Forbidden container'
);
}
}
// 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
[
$this
->
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'
]);
}
}
$response
->
setPagingToken
(
$this
->
limit
+
$this
->
offset
)
->
setAttribute
(
'fallbackAt'
,
$fallbackAt
);
return
$response
;
}
...
...
This diff is collapsed.
Core/Feeds/FeedsProvider.php
View file @
ad8aba3d
...
...
@@ -8,6 +8,10 @@ class FeedsProvider extends Provider
{
public
function
register
()
{
$this
->
di
->
bind
(
'Feeds\FeedCollection'
,
function
(
$di
)
{
return
new
FeedCollection
();
},
[
'useFactory'
=>
true
]);
$this
->
di
->
bind
(
'Feeds\Elastic\Manager'
,
function
(
$di
)
{
return
new
Elastic\Manager
();
});
...
...
This diff is collapsed.
Core/Hashtags/User/Manager.php
View file @
ad8aba3d
...
...
@@ -148,6 +148,16 @@ class Manager
return
array_slice
(
array_values
(
$output
),
0
,
count
(
$selected
)
+
$opts
[
'limit'
]);
}
/**
* @param array $opts
* @return array
* @throws \Exception
*/
public
function
values
(
array
$opts
=
[])
{
return
array_column
(
$this
->
get
(
$opts
)
?:
[],
'value'
);
}
/**
* @param HashtagEntity[] $hashtags
* @return bool
...
...
This diff is collapsed.
Please
register
or
sign in
to comment