Skip to content
GitLab
Menu
Why GitLab
Pricing
Contact Sales
Explore
Why GitLab
Pricing
Contact Sales
Explore
Sign in
Get free trial
Commits on Source (2)
Moderation summons queue
· 93e375c0
Emiliano Balbuena
authored
May 17, 2019
and
Mark Harding
committed
May 17, 2019
93e375c0
Merge branch 'goal/ReportingAndModeration.summons-queue' into 'epic/ReportingAndModeration'
· ca945dff
Mark Harding
authored
May 17, 2019
Moderation summons queue See merge request
!166
ca945dff
Hide whitespace changes
Inline
Side-by-side
Controllers/Cli/Moderation.php
View file @
ca945dff
...
...
@@ -5,6 +5,7 @@ namespace Minds\Controllers\Cli;
use
Minds\Core
;
use
Minds\Core\Di\Di
;
use
Minds\Cli
;
use
Minds\Core\Reports\Summons\Summon
;
use
Minds\Interfaces
;
use
Minds\Entities
;
...
...
@@ -47,9 +48,16 @@ class Moderation extends Cli\Controller implements Interfaces\CliControllerInter
$userId
=
$this
->
getOpt
(
'user'
);
$reportUrn
=
$this
->
getOpt
(
'report'
);
$juryType
=
$this
->
getOpt
(
'jury-type'
)
??
null
;
$respond
=
$this
->
getOpt
(
'respond'
)
??
null
;
if
(
!
$userId
||
!
$reportUrn
)
{
$this
->
out
(
'Usage: cli.php moderation summon --user=<username_or_guid> --report=<report_urn>'
);
$this
->
out
([
'Usage:'
,
'- Summoning: cli.php moderation summon --user=<username_or_guid> --report=<report_urn>'
,
'- Responding: cli.php moderation summon --user=<username_or_guid> --report=<report_urn> --jury-type=<initial_jury|appeal_jury> --respond=<accepted|declined>'
,
]);
exit
(
1
);
}
...
...
@@ -60,6 +68,54 @@ class Moderation extends Cli\Controller implements Interfaces\CliControllerInter
exit
(
1
);
}
if
(
!
$respond
)
{
$report
=
$reportsRepository
->
get
(
$reportUrn
);
if
(
!
$report
)
{
$this
->
out
(
'Error: Invalid report'
);
exit
(
1
);
}
$appeal
=
new
Core\Reports\Appeals\Appeal
();
$appeal
->
setReport
(
$report
);
$summonsManager
->
summon
(
$appeal
,
[
$user
->
guid
]);
$this
->
out
(
"Summoned
{
$user
->
guid
}
to
{
$reportUrn
}
"
);
}
else
{
$summon
=
new
Summon
();
$summon
->
setReportUrn
(
$reportUrn
)
->
setJuryType
(
$juryType
)
->
setJurorGuid
((
string
)
$user
->
guid
)
->
setStatus
(
$respond
);
$summonsManager
->
respond
(
$summon
);
$this
->
out
(
"Responded to
{
$user
->
guid
}
's summon to
{
$reportUrn
}
with
{
$respond
}
"
);
}
}
public
function
dev_only_simulate_summon
()
{
error_reporting
(
E_ALL
);
ini_set
(
'display_errors'
,
1
);
/** @var Core\Reports\Repository $reportsRepository */
$reportsRepository
=
Di
::
_
()
->
get
(
'Reports\Repository'
);
/** @var Core\Reports\Summons\Manager $summonsManager */
$summonsManager
=
Di
::
_
()
->
get
(
'Moderation\Summons\Manager'
);
$reportUrn
=
$this
->
getOpt
(
'report'
);
if
(
!
$reportUrn
)
{
$this
->
out
([
'Usage: cli.php moderation dev_only_simulate_summon --report=<report_urn>'
,
]);
exit
(
1
);
}
$report
=
$reportsRepository
->
get
(
$reportUrn
);
if
(
!
$report
)
{
...
...
@@ -68,8 +124,12 @@ class Moderation extends Cli\Controller implements Interfaces\CliControllerInter
}
$appeal
=
new
Core\Reports\Appeals\Appeal
();
$appeal
->
setReport
(
$report
);
$appeal
->
setReport
(
$report
)
->
setOwnerGuid
(
$report
->
getEntityOwnerGuid
());
$cohort
=
$summonsManager
->
summon
(
$appeal
,
null
);
$summonsManager
->
summon
(
$appeal
,
[
$user
->
guid
]
);
var_dump
(
$cohort
);
}
}
Controllers/api/v2/moderation/summons.php
View file @
ca945dff
...
...
@@ -53,6 +53,8 @@ class summons implements Interfaces\Api
->
setJuryType
(
$juryType
)
->
setJurorGuid
((
string
)
$userGuid
)
->
setStatus
(
$status
);
$summonsManager
->
respond
(
$summon
);
}
catch
(
\Exception
$e
)
{
return
Factory
::
response
([
'status'
=>
'error'
,
...
...
@@ -60,15 +62,6 @@ class summons implements Interfaces\Api
]);
}
if
(
!
$summonsManager
->
isSummoned
(
$summon
))
{
return
Factory
::
response
([
'status'
=>
'error'
,
'message'
=>
'You\'re not summoned'
,
]);
}
$summonsManager
->
respond
(
$summon
);
$response
=
[
'summon'
=>
$summon
->
getStatus
(),
'expires_in'
=>
$summon
->
getTtl
(),
...
...
Core/Queue/Runners/ReportsAppealSummon.php
View file @
ca945dff
...
...
@@ -12,6 +12,7 @@ use Minds\Core\Queue\Message;
use
Minds\Core\Queue\Client
;
use
Minds\Core\Queue\Interfaces\QueueClient
;
use
Minds\Core\Queue\Interfaces\QueueRunner
;
use
Minds\Core\Reports\Appeals\Appeal
;
use
Minds\Core\Reports\Summons\Manager
;
class
ReportsAppealSummon
implements
QueueRunner
...
...
@@ -31,7 +32,10 @@ class ReportsAppealSummon implements QueueRunner
->
receive
(
function
(
Message
$data
)
{
$params
=
$data
->
getData
();
/** @var Appeal $appeal */
$appeal
=
$params
[
'appeal'
]
??
null
;
/** @var string[] $cohort */
$cohort
=
$params
[
'cohort'
]
??
null
;
if
(
!
$appeal
)
{
...
...
@@ -39,9 +43,18 @@ class ReportsAppealSummon implements QueueRunner
return
;
}
echo
"Summoning for
{
$appeal
->
getReport
()
->
getUrn
()
}
..."
.
PHP_EOL
;
/** @var Manager $manager */
$manager
=
Di
::
_
()
->
get
(
'Moderation\Summons\Manager'
);
$manager
->
summon
(
$appeal
,
$cohort
);
$missing
=
$manager
->
summon
(
$appeal
,
$cohort
);
if
(
$missing
>
0
)
{
echo
"Missing
{
$missing
}
juror(s). Deferring..."
.
PHP_EOL
;
$manager
->
defer
(
$appeal
);
}
echo
"Done!"
.
PHP_EOL
;
});
}
}
Core/Reports/Summons/Cohort.php
View file @
ca945dff
...
...
@@ -7,149 +7,91 @@
namespace
Minds\Core\Reports\Summons
;
use
Minds\Core\Data\ElasticSearch\Client
as
ElasticsearchClient
;
use
Minds\Core\Data\ElasticSearch\Prepared\Search
;
use
Minds\Core\Di\Di
;
use
Minds\Helpers\Text
;
use
Exception
;
class
Cohort
{
/** @var
ElasticsearchClient
*/
protected
$
elasticsearch
;
/** @var
Repository
*/
protected
$
repository
;
/** @var
string
*/
protected
$
index
;
/** @var
Pool
*/
protected
$
pool
;
/**
*
Reposit
or
y
constructor.
* @param
ElasticsearchClient $elasticsearch
* @param
string $index
*
Coh
or
t
constructor.
* @param
Repository $repository
* @param
Pool $pool
*/
public
function
__construct
(
$
elasticsearch
=
null
,
$
index
=
null
$
repository
=
null
,
$
pool
=
null
)
{
$this
->
elasticsearch
=
$elasticsearch
?:
Di
::
_
()
->
get
(
'Database\ElasticSearch'
);
$this
->
index
=
$index
?:
'minds-metrics-*'
;
$this
->
repository
=
$repository
?:
new
Repository
(
);
$this
->
pool
=
$pool
?:
new
Pool
()
;
}
/**
* @param array $opts
* @return
\Generator
* @
yields string
* @return
string[]
* @
throws Exception
*/
public
function
getList
(
array
$opts
=
[]
)
public
function
pick
(
$opts
)
{
$opts
=
array_merge
([
'size'
=>
0
,
'for'
=>
null
,
'active_threshold'
=>
0
,
'platform'
=>
null
,
'validated'
=>
false
,
'limit'
=>
10
,
'offset'
=>
0
,
'except'
=>
[],
'active_threshold'
=>
null
,
],
$opts
);
$now
=
(
int
)
(
microtime
(
true
)
*
1000
);
$fromTimestamp
=
$now
-
(
$opts
[
'active_threshold'
]
*
1000
);
$body
=
[
'_source'
=>
[
'user_guid'
,
],
'query'
=>
[
'bool'
=>
[
'must'
=>
[
[
'range'
=>
[
'@timestamp'
=>
[
'gte'
=>
$fromTimestamp
,
],
],
],
[
'term'
=>
[
'type'
=>
'action'
,
],
],
],
],
],
'aggs'
=>
[
'entities'
=>
[
'terms'
=>
[
'field'
=>
'user_guid.keyword'
,
'size'
=>
$opts
[
'limit'
],
],
],
],
'size'
=>
0
,
];
if
(
$opts
[
'platform'
])
{
$body
[
'query'
][
'bool'
][
'must'
][]
=
[
'terms'
=>
[
'platform'
=>
Text
::
buildArray
(
$opts
[
'platform'
]),
],
];
}
if
(
$opts
[
'for'
])
{
if
(
!
isset
(
$body
[
'query'
][
'bool'
][
'must_not'
]))
{
$body
[
'query'
][
'bool'
][
'must_not'
]
=
[];
}
$cohort
=
[];
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'term'
=>
[
'user_guid'
=>
(
string
)
$opts
[
'for'
],
],
];
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'terms'
=>
[
'user_guid'
=>
[
'index'
=>
'minds-graph'
,
'type'
=>
'subscriptions'
,
'id'
=>
(
string
)
$opts
[
'for'
],
'path'
=>
'guids'
,
],
],
];
}
// Uncomment below to scale
// $poolSize = $opts['size'] * 5;
// $max_pages = 20; // NOTE: Normally capped to 20.
if
(
$opts
[
'validated'
])
{
$body
[
'query'
][
'bool'
][
'must'
][]
=
[
'exists'
=>
[
'field'
=>
'user_phone_number_hash'
,
],
];
$poolSize
=
400
;
$max_pages
=
1
;
// NOTE: Normally capped to 20.
$page
=
0
;
if
(
!
isset
(
$body
[
'query'
][
'bool'
][
'must_not'
]))
{
$body
[
'query'
][
'bool'
][
'must_not'
]
=
[];
while
(
true
)
{
if
(
$page
>
$max_pages
)
{
// Max = PoolSize * MaxPages
error_log
(
'Cannot gather a cohort'
);
break
;
}
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'term'
=>
[
'user_phone_number_hash'
=>
''
,
],
];
}
$query
=
[
'index'
=>
$this
->
index
,
'type'
=>
'action'
,
'body'
=>
$body
,
'size'
=>
$opts
[
'limit'
],
'from'
=>
$opts
[
'offset'
],
];
$prepared
=
new
Search
();
$prepared
->
query
(
$query
);
$pool
=
$this
->
pool
->
getList
([
'active_threshold'
=>
$opts
[
'active_threshold'
],
'platform'
=>
'browser'
,
'for'
=>
$opts
[
'for'
],
'except'
=>
$opts
[
'except'
],
'validated'
=>
false
,
'size'
=>
$poolSize
,
'page'
=>
$page
,
'max_pages'
=>
$max_pages
,
]);
$j
=
0
;
foreach
(
$pool
as
$userGuid
)
{
$j
++
;
// TODO: Check subs
$cohort
[]
=
$userGuid
;
if
(
count
(
$cohort
)
>=
$opts
[
'size'
])
{
break
;
}
}
$result
=
$this
->
elasticsearch
->
request
(
$prepared
);
if
(
$j
===
0
||
count
(
$cohort
)
>=
$opts
[
'size'
])
{
break
;
}
foreach
(
$result
[
'aggregations'
][
'entities'
][
'buckets'
]
as
$bucket
)
{
yield
$bucket
[
'key'
];
$page
++
;
}
return
$cohort
;
}
}
Core/Reports/Summons/Delegates/SocketDelegate.php
View file @
ca945dff
...
...
@@ -7,6 +7,7 @@
namespace
Minds\Core\Reports\Summons\Delegates
;
use
Exception
;
use
Minds\Core\Reports\Summons\Summon
;
use
Minds\Core\Sockets\Events
as
SocketEvents
;
...
...
@@ -28,7 +29,7 @@ class SocketDelegate
/**
* @param Summon $summon
* @throws
\
Exception
* @throws Exception
*/
public
function
onSummon
(
Summon
$summon
)
{
...
...
Core/Reports/Summons/Manager.php
View file @
ca945dff
...
...
@@ -7,6 +7,10 @@
namespace
Minds\Core\Reports\Summons
;
use
Exception
;
use
Minds\Core\Queue\Client
as
QueueClient
;
use
Minds\Core\Queue\Client
;
use
Minds\Core\Queue\Runners\ReportsAppealSummon
;
use
Minds\Core\Reports\Appeals\Appeal
;
use
Minds\Core\Reports\Summons\Delegates
;
...
...
@@ -15,9 +19,12 @@ class Manager
/** @var Cohort $cohort */
protected
$cohort
;
/** @va
t
Repository $repository */
/** @va
r
Repository $repository */
protected
$repository
;
/** @var QueueClient */
protected
$queueClient
;
/** @var Delegates\SocketDelegate $socketDelegate */
protected
$socketDelegate
;
...
...
@@ -25,39 +32,75 @@ class Manager
* Manager constructor.
* @param Cohort $cohort
* @param Repository $repository
* @param QueueClient $queueClient
* @param Delegates\SocketDelegate $socketDelegate
* @throws Exception
*/
public
function
__construct
(
$cohort
=
null
,
$repository
=
null
,
$queueClient
=
null
,
$socketDelegate
=
null
)
{
$this
->
cohort
=
$cohort
?:
new
Cohort
();
$this
->
repository
=
$repository
?:
new
Repository
();
$this
->
queueClient
=
$queueClient
?:
Client
::
build
();
$this
->
socketDelegate
=
$socketDelegate
?:
new
Delegates\SocketDelegate
();
}
/**
* @param Appeal $appeal
* @param array $cohort
* @throws \Exception
* @return int
* @throws Exception
*/
public
function
summon
(
Appeal
$appeal
,
$cohort
=
null
)
{
$cohort
=
$cohort
?:
$this
->
cohort
->
getList
([
'active_threshold'
=>
5
*
60
,
'platform'
=>
'browser'
,
'for'
=>
$appeal
->
getOwnerGuid
(),
'validated'
=>
true
,
'limit'
=>
12
,
]);
$reportUrn
=
$appeal
->
getReport
()
->
getUrn
();
$juryType
=
'appeal_jury'
;
$missing
=
0
;
if
(
!
$cohort
)
{
$jury
=
iterator_to_array
(
$this
->
repository
->
getList
([
'report_urn'
=>
$reportUrn
,
'jury_type'
=>
$juryType
,
]));
// Check how many are missing
$notDeclined
=
array_filter
(
$jury
,
function
(
Summon
$summon
)
{
return
$summon
->
isAccepted
()
||
$summon
->
isAwaiting
();
});
$missing
=
12
-
count
(
$notDeclined
);
// If we have a full jury, don't summon
if
(
$missing
<=
0
)
{
return
0
;
}
// Reduce jury to juror guids and try to pick up to missing size
$juryGuids
=
array_map
(
function
(
Summon
$summon
)
{
return
(
string
)
$summon
->
getJurorGuid
();
},
$jury
);
$cohort
=
$this
->
cohort
->
pick
([
'size'
=>
$missing
,
'for'
=>
$appeal
->
getOwnerGuid
(),
'except'
=>
$juryGuids
,
'active_threshold'
=>
5
*
60
,
]);
}
foreach
(
$cohort
as
$juror
)
{
$summon
=
new
Summon
();
$summon
->
setReportUrn
(
$
appeal
->
getReport
()
->
ge
tUrn
()
)
->
setJuryType
(
'appeal_jury'
)
->
setReportUrn
(
$
repor
tUrn
)
->
setJuryType
(
$juryType
)
->
setJurorGuid
(
$juror
)
->
setTtl
(
120
)
->
setStatus
(
'awaiting'
);
...
...
@@ -65,6 +108,8 @@ class Manager
$this
->
repository
->
add
(
$summon
);
$this
->
socketDelegate
->
onSummon
(
$summon
);
}
return
$missing
;
}
/**
...
...
@@ -79,9 +124,14 @@ class Manager
/**
* @param Summon $summon
* @return Summon
* @throws Exception
*/
public
function
respond
(
Summon
$summon
)
{
if
(
!
$this
->
isSummoned
(
$summon
))
{
throw
new
Exception
(
'User is not summoned'
);
}
$summon
->
setTtl
(
10
*
60
);
...
...
@@ -89,4 +139,30 @@ class Manager
return
$summon
;
}
/**
* @param string $reportUrn
* @param string $juryType
* @return bool
* @throws Exception
*/
public
function
release
(
$reportUrn
,
$juryType
)
{
return
$this
->
repository
->
deleteAll
([
'report_urn'
=>
$reportUrn
,
'jury_type'
=>
$juryType
,
]);
}
/**
* @param Appeal $appeal
*/
public
function
defer
(
Appeal
$appeal
)
{
$this
->
queueClient
->
setQueue
(
ReportsAppealSummon
::
class
)
->
send
([
'appeal'
=>
$appeal
,
],
600
);
}
}
Core/Reports/Summons/Pool.php
0 → 100644
View file @
ca945dff
<?php
/**
* User Pool for Cohort
*
* @author edgebal
*/
namespace
Minds\Core\Reports\Summons
;
use
Generator
;
use
Minds\Core\Data\ElasticSearch\Client
as
ElasticsearchClient
;
use
Minds\Core\Data\ElasticSearch\Prepared\Search
;
use
Minds\Core\Di\Di
;
use
Minds\Helpers\Text
;
class
Pool
{
/** @var ElasticsearchClient */
protected
$elasticsearch
;
/** @var string */
protected
$index
;
/**
* Repository constructor.
* @param ElasticsearchClient $elasticsearch
* @param string $index
*/
public
function
__construct
(
$elasticsearch
=
null
,
$index
=
null
)
{
$this
->
elasticsearch
=
$elasticsearch
?:
Di
::
_
()
->
get
(
'Database\ElasticSearch'
);
$this
->
index
=
$index
?:
'minds-metrics-*'
;
}
/**
* @param array $opts
* @return Generator
* @yields string
*/
public
function
getList
(
array
$opts
=
[])
{
$opts
=
array_merge
([
'for'
=>
null
,
'active_threshold'
=>
0
,
'platform'
=>
null
,
'validated'
=>
false
,
'size'
=>
10
,
'page'
=>
0
,
'max_pages'
=>
20
,
],
$opts
);
$now
=
(
int
)
(
microtime
(
true
)
*
1000
);
$fromTimestamp
=
$now
-
(
$opts
[
'active_threshold'
]
*
1000
);
$body
=
[
'_source'
=>
[
'user_guid'
,
],
'query'
=>
[
'bool'
=>
[
'must'
=>
[
[
'range'
=>
[
'@timestamp'
=>
[
'gte'
=>
$fromTimestamp
,
],
],
],
[
'term'
=>
[
'type'
=>
'action'
,
],
],
],
],
],
'aggs'
=>
[
'entities'
=>
[
'terms'
=>
[
'field'
=>
'user_guid.keyword'
,
'size'
=>
$opts
[
'size'
],
'include'
=>
[
'partition'
=>
$opts
[
'page'
],
'num_partitions'
=>
$opts
[
'max_pages'
],
],
],
],
],
'size'
=>
0
,
];
if
(
$opts
[
'platform'
])
{
$body
[
'query'
][
'bool'
][
'must'
][]
=
[
'terms'
=>
[
'platform'
=>
Text
::
buildArray
(
$opts
[
'platform'
]),
],
];
}
if
(
$opts
[
'for'
])
{
if
(
!
isset
(
$body
[
'query'
][
'bool'
][
'must_not'
]))
{
$body
[
'query'
][
'bool'
][
'must_not'
]
=
[];
}
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'term'
=>
[
'user_guid'
=>
(
string
)
$opts
[
'for'
],
],
];
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'terms'
=>
[
'user_guid'
=>
[
'index'
=>
'minds-graph'
,
'type'
=>
'subscriptions'
,
'id'
=>
(
string
)
$opts
[
'for'
],
'path'
=>
'guids'
,
],
],
];
}
if
(
$opts
[
'except'
])
{
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'terms'
=>
[
'user_guid'
=>
$opts
[
'except'
],
],
];
}
if
(
$opts
[
'validated'
])
{
$body
[
'query'
][
'bool'
][
'must'
][]
=
[
'exists'
=>
[
'field'
=>
'user_phone_number_hash'
,
],
];
if
(
!
isset
(
$body
[
'query'
][
'bool'
][
'must_not'
]))
{
$body
[
'query'
][
'bool'
][
'must_not'
]
=
[];
}
$body
[
'query'
][
'bool'
][
'must_not'
][]
=
[
'term'
=>
[
'user_phone_number_hash'
=>
''
,
],
];
}
$query
=
[
'index'
=>
$this
->
index
,
'type'
=>
'action'
,
'body'
=>
$body
,
];
$prepared
=
new
Search
();
$prepared
->
query
(
$query
);
$result
=
$this
->
elasticsearch
->
request
(
$prepared
);
foreach
(
$result
[
'aggregations'
][
'entities'
][
'buckets'
]
as
$bucket
)
{
yield
$bucket
[
'key'
];
}
}
}
Core/Reports/Summons/Repository.php
View file @
ca945dff
...
...
@@ -8,6 +8,8 @@
namespace
Minds\Core\Reports\Summons
;
use
Cassandra\Bigint
;
use
Exception
;
use
Generator
;
use
Minds\Core\Data\Cassandra\Client
as
CassandraClient
;
use
Minds\Core\Data\Cassandra\Prepared\Custom
;
use
Minds\Core\Di\Di
;
...
...
@@ -30,11 +32,70 @@ class Repository
/**
* @param array $opts
* @throws \NotImplementedException
* @return Generator
* @yields array
* @throws Exception
*/
public
function
getList
(
array
$opts
=
[])
{
throw
new
\NotImplementedException
();
$opts
=
array_merge
([
'report_urn'
=>
null
,
'jury_type'
=>
null
,
'juror_guid'
=>
null
,
'limit'
=>
10000
,
'offset'
=>
null
,
],
$opts
);
if
(
!
$opts
[
'report_urn'
])
{
throw
new
Exception
(
'Invalid Report URN'
);
}
if
(
!
$opts
[
'jury_type'
])
{
throw
new
Exception
(
'Invalid Jury type'
);
}
$cql
=
"SELECT * FROM moderation_summons WHERE report_urn = ? AND jury_type = ?"
;
$values
=
[
$opts
[
'report_urn'
],
$opts
[
'jury_type'
],
];
$cqlOpts
=
[];
if
(
$opts
[
'juror_guid'
])
{
$cql
.
=
" AND juror_guid = ?"
;
$values
[]
=
new
Bigint
(
$opts
[
'juror_guid'
]);
}
if
(
$opts
[
'offset'
])
{
$cqlOpts
[
'paging_state_token'
]
=
base64_decode
(
$opts
[
'offset'
]);
}
if
(
$opts
[
'limit'
])
{
$cqlOpts
[
'page_size'
]
=
(
int
)
$opts
[
'limit'
];
}
$prepared
=
new
Custom
();
$prepared
->
query
(
$cql
,
$values
);
$prepared
->
setOpts
(
$cqlOpts
);
try
{
$rows
=
$this
->
db
->
request
(
$prepared
);
foreach
(
$rows
as
$row
)
{
$summon
=
new
Summon
();
$summon
->
setReportUrn
(
$row
[
'report_urn'
])
->
setJuryType
(
$row
[
'jury_type'
])
->
setJurorGuid
(
$row
[
'juror_guid'
]
->
toInt
())
->
setStatus
(
$row
[
'status'
])
->
setTtl
(
$row
[
'expires'
]
-
time
());
yield
$summon
;
}
}
catch
(
Exception
$e
)
{
error_log
(
$e
);
return
[];
}
}
/**
...
...
@@ -60,7 +121,7 @@ class Repository
try
{
return
(
bool
)
$this
->
db
->
request
(
$prepared
,
true
);
}
catch
(
\
Exception
$e
)
{
}
catch
(
Exception
$e
)
{
error_log
(
$e
);
return
false
;
}
...
...
@@ -86,7 +147,7 @@ class Repository
$response
=
$this
->
db
->
request
(
$prepared
);
return
$response
[
0
][
'total'
]
>
0
;
}
catch
(
\
Exception
$e
)
{
}
catch
(
Exception
$e
)
{
error_log
(
$e
);
return
false
;
}
...
...
@@ -94,10 +155,59 @@ class Repository
/**
* @param Summon $summon
* @throws \NotImplementedException
* @return bool
* @throws Exception
*/
public
function
delete
(
Summon
$summon
)
{
throw
new
\NotImplementedException
();
return
$this
->
deleteAll
([
'report_urn'
=>
$summon
->
getReportUrn
(),
'jury_type'
=>
$summon
->
getJuryType
(),
'juror_guid'
=>
$summon
->
getJurorGuid
(),
]);
}
/**
* @param array $opts
* @return bool
* @throws Exception
* @yields array
*/
public
function
deleteAll
(
array
$opts
=
[])
{
$opts
=
array_merge
([
'report_urn'
=>
null
,
'jury_type'
=>
null
,
'juror_guid'
=>
null
,
],
$opts
);
if
(
!
$opts
[
'report_urn'
])
{
throw
new
Exception
(
'Invalid Report URN'
);
}
if
(
!
$opts
[
'jury_type'
])
{
throw
new
Exception
(
'Invalid Jury type'
);
}
$cql
=
"DELETE FROM moderation_summons WHERE report_urn = ? AND jury_type = ?"
;
$values
=
[
$opts
[
'report_urn'
],
$opts
[
'jury_type'
],
];
if
(
$opts
[
'juror_guid'
])
{
$cql
.
=
" AND juror_guid = ?"
;
$values
[]
=
new
Bigint
(
$opts
[
'juror_guid'
]);
}
$prepared
=
new
Custom
();
$prepared
->
query
(
$cql
,
$values
);
try
{
return
(
bool
)
$this
->
db
->
request
(
$prepared
,
true
);
}
catch
(
Exception
$e
)
{
error_log
(
$e
);
return
false
;
}
}
}
Core/Reports/Summons/Summon.php
View file @
ca945dff
...
...
@@ -7,6 +7,8 @@
namespace
Minds\Core\Reports\Summons
;
use
Exception
;
use
JsonSerializable
;
use
Minds\Traits\MagicAttributes
;
/**
...
...
@@ -22,7 +24,7 @@ use Minds\Traits\MagicAttributes;
* @method int getTtl()
* @method Summon setTtl(int $ttl)
*/
class
Summon
implements
\
JsonSerializable
class
Summon
implements
JsonSerializable
{
use
MagicAttributes
;
...
...
@@ -44,12 +46,12 @@ class Summon implements \JsonSerializable
/**
* @param string $status
* @return $this
* @throws
\
Exception
* @throws Exception
*/
public
function
setStatus
(
$status
)
{
if
(
!
in_array
(
$status
,
[
'awaiting'
,
'accepted'
,
'declined'
]))
{
throw
new
\
Exception
(
'Invalid status'
);
throw
new
Exception
(
'Invalid status'
);
}
$this
->
status
=
$status
;
...
...
Core/Reports/Verdict/Delegates/ReleaseSummonsesDelegate.php
0 → 100644
View file @
ca945dff
<?php
/**
* ReleaseSummonsesDelegate
*
* @author edgebal
*/
namespace
Minds\Core\Reports\Verdict\Delegates
;
use
Minds\Core\Di\Di
;
use
Minds\Core\Reports\Summons\Manager
;
use
Minds\Core\Reports\Verdict\Verdict
;
class
ReleaseSummonsesDelegate
{
/** @var Manager */
protected
$summonsManager
;
/**
* ReleaseSummonsesDelegate constructor.
* @param Manager $summonsManager
*/
public
function
__construct
(
$summonsManager
=
null
)
{
$this
->
summonsManager
=
$summonsManager
?:
Di
::
_
()
->
get
(
'Moderation\Summons\Manager'
);
}
/**
* @param Verdict $verdict
* @throws \Exception
*/
public
function
onCast
(
Verdict
$verdict
)
{
$juryType
=
$verdict
->
isAppeal
()
?
'appeal_jury'
:
'initial_jury'
;
$this
->
summonsManager
->
release
(
$verdict
->
getReport
()
->
getUrn
(),
$juryType
);
}
}
Core/Reports/Verdict/Manager.php
View file @
ca945dff
...
...
@@ -32,17 +32,22 @@ class Manager
/** @var Delegates\NotificationDelegate $notificationDelegate */
private
$notificationDelegate
;
/** @var Delegates\ReleaseSummonsesDelegate $releaseSummonsesDelegate */
private
$releaseSummonsesDelegate
;
public
function
__construct
(
$repository
=
null
,
$actionDelegate
=
null
,
$reverseActionDelegate
=
null
,
$notificationDelegate
=
null
$notificationDelegate
=
null
,
$releaseSummonsesDelegate
=
null
)
{
$this
->
repository
=
$repository
?:
new
Repository
;
$this
->
actionDelegate
=
$actionDelegate
?:
new
Delegates\ActionDelegate
;
$this
->
reverseActionDelegate
=
$reverseActionDelegate
?:
new
Delegates\ReverseActionDelegate
;
$this
->
notificationDelegate
=
$notificationDelegate
?:
new
Delegates\NotificationDelegate
;
$this
->
releaseSummonsesDelegate
=
$releaseSummonsesDelegate
?:
new
Delegates\ReleaseSummonsesDelegate
;
}
/**
...
...
@@ -119,6 +124,7 @@ class Manager
* Cast a verdict
* @param Verdict $verdict
* @return boolean
* @throws \Exception
*/
public
function
cast
(
Verdict
$verdict
)
{
...
...
@@ -133,6 +139,9 @@ class Manager
// Send a notification to the reported user
$this
->
notificationDelegate
->
onAction
(
$verdict
);
// Release summonses
$this
->
releaseSummonsesDelegate
->
onCast
(
$verdict
);
// Send rewards to reporters
return
$added
;
...
...
Core/Reports/Verdict/Verdict.php
View file @
ca945dff
...
...
@@ -4,16 +4,16 @@
*/
namespace
Minds\Core\Reports\Verdict
;
use
Minds\Core\Reports\Jury\Decision
;
use
Minds\Core\Reports\Report
;
use
Minds\Traits\MagicAttributes
;
/**
* @method Report getReport(): Report
* @method Report getDecisions(): array<Decision>
* @method Report isAppeal(): boolean
* @method Report isUphold(): boolean
* @method Report getAction(): string
* @method Report getInitialJuryAction(): string
* @method Report getTimestamp: int
* @method Report getReport()
* @method boolean isUphold()
* @method string getAction()
* @method string getInitialJuryAction()
* @method int getTimestamp()
*/
class
Verdict
{
...
...
@@ -36,7 +36,7 @@ class Verdict
/**
* Decisions
* @return
array<
Decision
>
* @return Decision
[]
*/
public
function
getDecisions
()
{
...
...
Spec/Core/Reports/Verdict/ManagerSpec.php
View file @
ca945dff
...
...
@@ -18,19 +18,22 @@ class ManagerSpec extends ObjectBehavior
private
$actionDelegate
;
private
$reverseDelegate
;
private
$notificationDelegate
;
private
$releaseSummonsesDelegate
;
function
let
(
Repository
$repository
,
Delegates
\ActionDelegate
$actionDelegate
,
Delegates
\ReverseActionDelegate
$reverseDelegate
,
Delegates
\NotificationDelegate
$notificationDelegate
Delegates
\NotificationDelegate
$notificationDelegate
,
Delegates
\ReleaseSummonsesDelegate
$releaseSummonsesDelegate
)
{
$this
->
beConstructedWith
(
$repository
,
$actionDelegate
,
$reverseDelegate
,
$notificationDelegate
);
$this
->
beConstructedWith
(
$repository
,
$actionDelegate
,
$reverseDelegate
,
$notificationDelegate
,
$releaseSummonsesDelegate
);
$this
->
repository
=
$repository
;
$this
->
actionDelegate
=
$actionDelegate
;
$this
->
reverseDelegate
=
$reverseDelegate
;
$this
->
notificationDelegate
=
$notificationDelegate
;
$this
->
releaseSummonsesDelegate
=
$releaseSummonsesDelegate
;
}
...
...
@@ -60,6 +63,9 @@ class ManagerSpec extends ObjectBehavior
$this
->
notificationDelegate
->
onAction
(
$verdict
)
->
shouldBeCalled
();
$this
->
releaseSummonsesDelegate
->
onCast
(
$verdict
)
->
shouldBeCalled
();
$this
->
cast
(
$verdict
->
getWrappedObject
());
}
...
...