Skip to content

Commit c3328a9

Browse files
committed
Merge pull request #672 from LearningLocker/develop
v1.5.3
2 parents 33cca0f + 5d26613 commit c3328a9

File tree

9 files changed

+133
-70
lines changed

9 files changed

+133
-70
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.5.2
1+
1.5.3

app/controllers/api/Statements.php

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ public function __construct(QueryRepository $query) {
2020
*/
2121
public function where() {
2222
$limit = \LockerRequest::getParam('limit', 100);
23-
$filters = json_decode(
24-
\LockerRequest::getParam('filters'),
25-
true
26-
) ?: [];
23+
$filters = $this->getParam('filters');
2724
return \Response::json($this->query->where($this->lrs->_id, $filters)->paginate($limit));
2825
}
2926

@@ -32,10 +29,7 @@ public function where() {
3229
* @return Aggregate http://php.net/manual/en/mongocollection.aggregate.php#refsect1-mongocollection.aggregate-examples
3330
*/
3431
public function aggregate() {
35-
$pipeline = json_decode(
36-
\LockerRequest::getParam('pipeline'),
37-
true
38-
) ?: [['$match' => ['active' => true]]];
32+
$pipeline = $this->getParam('pipeline');
3933
return \Response::json($this->query->aggregate($this->lrs->_id, $pipeline));
4034
}
4135

@@ -44,10 +38,7 @@ public function aggregate() {
4438
* @return Aggregate http://php.net/manual/en/mongocollection.aggregate.php#refsect1-mongocollection.aggregate-examples
4539
*/
4640
public function aggregateTime() {
47-
$match = json_decode(
48-
\LockerRequest::getParam('match'),
49-
true
50-
) ?: [];
41+
$match = $this->getParam('match');
5142
return \Response::json($this->query->aggregateTime($this->lrs->_id, $match));
5243
}
5344

@@ -56,10 +47,7 @@ public function aggregateTime() {
5647
* @return Aggregate http://php.net/manual/en/mongocollection.aggregate.php#refsect1-mongocollection.aggregate-examples
5748
*/
5849
public function aggregateObject() {
59-
$match = json_decode(
60-
\LockerRequest::getParam('match'),
61-
true
62-
) ?: [];
50+
$match = $this->getParam('match');
6351
return \Response::json($this->query->aggregateObject($this->lrs->_id, $match));
6452
}
6553

@@ -79,4 +67,20 @@ public function index(){
7967

8068
return $this->returnJson($data);
8169
}
70+
71+
public function void() {
72+
$match = $this->getParam('match');
73+
return \Response::json($this->query->void($match, $this->getOptions()));
74+
}
75+
76+
private function getParam($param) {
77+
$param_value = \LockerRequest::getParam($param);
78+
$value = json_decode($param_value, true);
79+
if ($value === null && $param_value === null) {
80+
throw new Exceptions\Exception("Expected `$param` to be defined as a URL parameter.");
81+
} else if ($value === null) {
82+
throw new Exceptions\Exception("Expected the value of `$param` to be valid JSON in the URL parameter.");
83+
}
84+
return $value;
85+
}
8286
}

app/locker/repository/Query/EloquentQueryRepository.php

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php namespace Locker\Repository\Query;
22
use \Locker\Helpers\Helpers as Helpers;
3+
use \Locker\Repository\Statement\EloquentRepository as StatementsRepo;
34

45
class EloquentQueryRepository implements QueryRepository {
56

@@ -24,25 +25,25 @@ public function where($lrsId, array $filters) {
2425
case 'in': $statements->whereIn($filter[0], $filter[2]); break;
2526
case 'between': $statements->whereBetween($filter[0], [$filter[2], $filter[3]]); break;
2627
case 'or':
27-
if (!empty($filter[2]) && is_array($filter[2])) {
28-
$statements->where(function($query) use ($filter) {
29-
foreach ($filter[2] as $value) {
30-
foreach ($value[1] as $subVal) {
31-
if (is_object($subVal)) {
32-
$subVal_array = get_object_vars($subVal);
33-
$query->orWhere(function($query) use ($subVal_array, $value) {
34-
foreach ($subVal_array as $key => $val) {
35-
$query->where($value[0] . '.' . $key, '=', $val);
36-
}
37-
});
38-
} else {
39-
$query->orWhere($value[0], '=', $subVal);
40-
}
41-
}
42-
}
28+
if (!empty($filter[2]) && is_array($filter[2])) {
29+
$statements->where(function($query) use ($filter) {
30+
foreach ($filter[2] as $value) {
31+
foreach ($value[1] as $subVal) {
32+
if (is_object($subVal)) {
33+
$subVal_array = get_object_vars($subVal);
34+
$query->orWhere(function($query) use ($subVal_array, $value) {
35+
foreach ($subVal_array as $key => $val) {
36+
$query->where($value[0] . '.' . $key, '=', $val);
37+
}
4338
});
39+
} else {
40+
$query->orWhere($value[0], '=', $subVal);
41+
}
4442
}
45-
break;
43+
}
44+
});
45+
}
46+
break;
4647
default: $statements->where($filter[0], $filter[1], $filter[2]);
4748
}
4849
}
@@ -61,9 +62,12 @@ public function aggregate($lrsId, array $pipeline) {
6162
return;
6263
}
6364

64-
$pipeline[0] = array_merge_recursive([
65-
'$match' => [self::LRS_ID_KEY => $lrsId]
66-
], $pipeline[0]);
65+
$pipeline[0]['$match'] = [
66+
'$and' => [(object) $pipeline[0]['$match'], [
67+
self::LRS_ID_KEY => $lrsId,
68+
'active' => true
69+
]]
70+
];
6771

6872
return Helpers::replaceHtmlEntity($this->db->statements->aggregate($pipeline), true);
6973
}
@@ -120,6 +124,49 @@ public function aggregateObject($lrsId, array $match) {
120124
]]);
121125
}
122126

127+
public function void(array $match, array $opts) {
128+
$void_id = 'http://adlnet.gov/expapi/verbs/voided';
129+
$match = [
130+
'$and' => [$match, [
131+
'statement.verb.id' => ['$ne' => $void_id],
132+
'voided' => false
133+
]]
134+
];
135+
136+
$data = $this->aggregate($opts['lrs_id'], [[
137+
'$match' => $match
138+
], [
139+
'$project' => [
140+
'_id' => 0,
141+
'statement.id' => 1,
142+
]
143+
]]);
144+
145+
$statements = array_map(function ($result) use ($opts, $void_id) {
146+
return [
147+
'actor' => $opts['client']['authority'],
148+
'verb' => [
149+
'id' => $void_id,
150+
'display' => [
151+
'en' => 'voided'
152+
]
153+
],
154+
'object' => [
155+
'objectType' => 'StatementRef',
156+
'id' => $result['statement']['id']
157+
]
158+
];
159+
}, $data['result']);
160+
161+
$opts['authority'] = json_decode(json_encode($opts['client']['authority']));
162+
163+
if( count($statements) > 0 ){
164+
return (new StatementsRepo())->store(json_decode(json_encode($statements)), [], $opts);
165+
} else {
166+
return [];
167+
}
168+
}
169+
123170
/**
124171
* Query to grab the required data based on type
125172
*
@@ -144,19 +191,19 @@ public function selectDistinctField( $lrs='', $table='', $field='', $value='', $
144191

145192
/**
146193
* Gets statement documents based on a filter.
147-
*
194+
*
148195
* @param $lrs id The Lrs to search in (required)
149196
* @param $filter array The filter array
150197
* @param $raw boolean Pagination or raw statements?
151198
* @param $sections array Sections of the statement to return, default = all
152-
*
199+
*
153200
* @return Statement query
154201
*/
155202
public function selectStatementDocs( $lrs='', $filter, $raw=false, $sections=[] ){
156203
$statements = \Statement::where('lrs._id', $lrs);
157204

158205
if( !empty($filter) ){
159-
206+
160207
foreach($filter as $key => $value ){
161208
if( is_array($value) ){
162209
//does the array contain between values? e.g. <> 3, 6
@@ -182,7 +229,7 @@ public function selectStatementDocs( $lrs='', $filter, $raw=false, $sections=[]
182229
* @param $filter array The filter array
183230
* @param $raw boolean Pagination or raw statements?
184231
* @param $sections array Sections of the statement to return, default = all
185-
*
232+
*
186233
* @return array results
187234
*
188235
**/
@@ -229,16 +276,16 @@ public function timedGrouping( $lrs, $filters, $interval, $type='time' ){
229276
$set_id = [ $interval => '$timestamp' ];
230277
}else{
231278
switch($type){
232-
case 'user':
233-
$set_id = ['actor' => '$statement.actor'];
234-
$project = ['$addToSet' => '$statement.actor'];
279+
case 'user':
280+
$set_id = ['actor' => '$statement.actor'];
281+
$project = ['$addToSet' => '$statement.actor'];
235282
break;
236-
case 'verb':
237-
$set_id = ['verb' => '$statement.verb'];
238-
$project = ['$addToSet' => '$statement.verb'];
283+
case 'verb':
284+
$set_id = ['verb' => '$statement.verb'];
285+
$project = ['$addToSet' => '$statement.verb'];
239286
break;
240-
case 'activity':
241-
$set_id = ['activity' => '$statement.object'];
287+
case 'activity':
288+
$set_id = ['activity' => '$statement.object'];
242289
$project = ['$addToSet' => '$statement.object'];
243290
break;
244291
}
@@ -290,8 +337,8 @@ public function timedGrouping( $lrs, $filters, $interval, $type='time' ){
290337
* Return grouped object based on criteria passed.
291338
*
292339
* @param $lrs
293-
* @param $section
294-
* @param $filters
340+
* @param $section
341+
* @param $filters
295342
* @param $returnFields
296343
*
297344
* @return $results

app/locker/repository/Statement/EloquentInserter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private function checkForConflict(\stdClass $statement, StoreOptions $opts) {
4747
* @param \stdClass $statement_y
4848
* @throws Exceptions\Conflict
4949
*/
50-
private function compareForConflict(\stdClass $statement_x, \stdClass $statement_y) {
50+
public function compareForConflict(\stdClass $statement_x, \stdClass $statement_y) {
5151
$matchable_x = $this->matchableStatement($statement_x);
5252
$matchable_y = $this->matchableStatement($statement_y);
5353
if ($matchable_x != $matchable_y) {

app/locker/repository/Statement/EloquentStorer.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public function store(array $statements, array $attachments, StoreOptions $opts)
5252
* @return [String => \stdClass] Array of statements mapped to their UUIDs.
5353
*/
5454
private function constructValidStatements(array $statements, StoreOptions $opts) {
55+
$generated_ids = [];
5556
$constructed = [];
5657
$this->hashes = [];
5758

@@ -64,7 +65,8 @@ private function constructValidStatements(array $statements, StoreOptions $opts)
6465
}
6566

6667
if (!isset($statement->id)) {
67-
$statement->id = $this->getUUID();
68+
$statement->id = $this->getUUID($generated_ids);
69+
$generated_ids[] = $statement->id;
6870
}
6971

7072
// Validates statement.
@@ -102,18 +104,25 @@ private function activateStatements(array $ids, StoreOptions $opts) {
102104

103105
/**
104106
* Generates a UUID.
107+
* @param $excludes An array of ids to check that the new id is unique against
105108
* @return String
106109
*/
107-
private function getUUID() {
110+
private function getUUID($exclude=[]) {
108111
$remote_addr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'LL';
109112
mt_srand(crc32(serialize([microtime(true), $remote_addr, 'ETC'])));
110113

111-
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
114+
$uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
112115
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
113116
mt_rand(0, 0xffff),
114117
mt_rand(0, 0x0fff) | 0x4000,
115118
mt_rand(0, 0x3fff) | 0x8000,
116119
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
117120
);
121+
122+
if( in_array($uuid, $exclude)){
123+
return $this->getUUID($exclude);
124+
} else {
125+
return $uuid;
126+
}
118127
}
119128
}

app/routes.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@
389389

390390
});
391391

392+
Route::group(['prefix' => 'api/v2', 'before' => 'auth.statement'], function () {
393+
Route::get('statements/void', ['uses' => 'Controllers\API\Statements@void']);
394+
});
395+
392396
/*
393397
|------------------------------------------------------------------
394398
| Learning Locker RESTful API

app/tests/routes/StatementsTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public function testAggregateObject() {
103103

104104
public function testWhere() {
105105
$response = $this->requestStatements('where', [
106-
'filter' => '[[{"active", true}]]',
106+
'filters' => '[["active", "=", true]]',
107107
'limit' => 1,
108108
'page' => 1
109109
]);

composer.json

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,26 +66,14 @@
6666
},
6767
"scripts": {
6868
"post-install-cmd": [
69-
"php composer.phar refresh"
69+
"sh refresh.sh"
7070
],
7171
"post-update-cmd": [
7272
"php artisan clear-compiled",
73-
"php composer.phar refresh"
73+
"sh refresh.sh"
7474
],
7575
"post-create-project-cmd": [
7676
"php artisan key:generate"
77-
],
78-
"refresh": [
79-
"php artisan optimize",
80-
"php artisan js-localization:refresh",
81-
"php composer.phar clean-bower"
82-
],
83-
"clean-bower": [
84-
"find public/assets/js/bower_components/ -type f -name '*.md' | xargs rm -f",
85-
"find public/assets/js/bower_components/ -type d -name 'docs' | xargs rm -rf",
86-
"find public/assets/js/bower_components/ -type d -name 'spec' | xargs rm -rf",
87-
"find public/assets/js/bower_components/ -type d -name 'test' | xargs rm -rf",
88-
"find public/assets/js/bower_components/ -type f -not \\( -name '*.css' -o -name '*.js' \\) | xargs rm -rf"
8977
]
9078
},
9179
"minimum-stability": "stable"

refresh.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
echo "Refreshing LL files"
2+
php artisan optimize
3+
php artisan js-localization:refresh
4+
5+
echo "Cleaning bower_components"
6+
find public/assets/js/bower_components/ -type f -name '*.md' | xargs rm -f
7+
find public/assets/js/bower_components/ -type d -name 'docs' | xargs rm -rf
8+
find public/assets/js/bower_components/ -type d -name 'spec' | xargs rm -rf
9+
find public/assets/js/bower_components/ -type d -name 'test' | xargs rm -rf
10+
find public/assets/js/bower_components/ -type f -not \( -name '*.css' -o -name '*.js' \) -print
11+
find public/assets/js/bower_components/ -type f -not \( -name '*.css' -o -name '*.js' \) | xargs rm -rf

0 commit comments

Comments
 (0)