Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

return [
'LOCAL_FILESTORE' => __DIR__.'/uploads',
'SESSION_FILESTORE' => __DIR__.'/app/storage/sessions',
'FS_REPO' => 'Local',
'FS_LOCAL_ENDPOINT' => __DIR__.'/uploads',
'LOG_FILESTORE' => __DIR__.'/app/storage/logs/laravel.log',
];
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
composer.phar
.DS_Store
Thumbs.db
.phpintel
.env.*.php

/app/config/ht2
/app/config/production
Expand Down
43 changes: 43 additions & 0 deletions app/commands/FileRepositoryCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Locker\Repository\File\Factory as FileFactory;

class FileRepositoryCommand extends Command {
protected $name = 'll:file-repo';
protected $description = 'Migrates files from one file repository (i.e. Local) to another (i.e. Rackspace).';

public function fire() {
$from_var = $this->option('from');
$to_var = $this->argument('to');
$from_repo = FileFactory::createRepo($from_var);
$to_repo = FileFactory::createRepo($to_var);
$files = $from_repo->index([]);

$count = 0;
foreach ($files as $file) {
$path = $file['path'];
if ($file['type'] === 'file' && !$to_repo->has($path, [])) {
$count += 1;
$to_repo->update($path, ['content' => $from_repo->show($path, [])], []);
echo "Migrated '{$path}' from '{$from_var}' to '{$to_var}'.".PHP_EOL;
}
}

echo "Migrated $count files and ignored ".(count($files) - $count).".".PHP_EOL;
}

protected function getArguments() {
return [
['to', InputArgument::REQUIRED, 'The repository to migrate to.']
];
}

protected function getOptions() {
return [
['from', 'f', InputOption::VALUE_OPTIONAL, 'The repository to migrate from.', 'Local'],
];
}

}
2 changes: 1 addition & 1 deletion app/config/session.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
|
*/

'files' => Helpers::getEnvVar('SESSION_FILESTORE'),
'files' => null,

/*
|--------------------------------------------------------------------------
Expand Down
20 changes: 11 additions & 9 deletions app/controllers/xapi/DocumentController.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?php namespace Controllers\xAPI;

use \Locker\Repository\Document\DocumentRepository as Document;
use \Carbon\Carbon;
use \Locker\Helpers\Exceptions as Exceptions;
use Locker\Repository\Document\DocumentRepository as Document;
use Carbon\Carbon;
use Locker\Helpers\Exceptions as Exceptions;
use Locker\Repository\File\Factory as FileFactory;

abstract class DocumentController extends BaseController {

Expand Down Expand Up @@ -238,11 +238,13 @@ public function documentResponse($data) {
case "text/plain":
return \Response::make($document->content, 200, $headers);
default:
return \Response::download(
$document->getFilePath(),
$document->content,
$headers
);
$stream = FileFactory::create()->stream($document->getFilePath(), []);
return \Response::stream(function () use ($stream) {
while (!feof($stream)) {
echo fread($stream, 8192); flush();ob_flush();
}
fclose($stream);
}, 200, $headers);
}
}
}
Expand Down
45 changes: 31 additions & 14 deletions app/controllers/xapi/StatementIndexController.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,21 @@ public function index($options) {
// Defines the content type and body of the response.
if ($opts['attachments'] === true) {
$content_type = 'multipart/mixed; boundary='.static::BOUNDARY;
$body = $this->makeAttachmentsResult($statements, $count, $opts);
$body = function () use ($statements, $count, $opts) {
return $this->makeAttachmentsResult($statements, $count, $opts);
};
} else {
$content_type = 'application/json;';
$body = $this->makeStatementsResult($statements, $count, $opts);
$body = function () use ($statements, $count, $opts) {
return $this->makeStatementsResult($statements, $count, $opts);
};
}

// Creates the response.
return \Response::make($body, 200, [
return \Response::stream($body, 200, [
'Content-Type' => $content_type,
'X-Experience-API-Consistent-Through' => Helpers::getCurrentDate()
]);;
]);
}

/**
Expand All @@ -83,7 +87,7 @@ private function makeStatementsResult(array $statements, $count, array $opts) {
'statements' => $statements
];

return json_encode($statement_result);
$this->emit(json_encode($statement_result));
}

/**
Expand All @@ -96,24 +100,37 @@ private function makeAttachmentsResult(array $statements, $count, array $opts) {
$boundary = static::BOUNDARY;
$eol = static::EOL;
$content_type = 'multipart/mixed; boundary='.$boundary;
$statement_result = "Content-Type:application/json$eol$eol".$this->makeStatementsResult(

$this->emit("--$boundary$eol");
$this->emit("Content-Type:application/json$eol$eol");
$this->makeStatementsResult(
$statements,
$count,
$opts
);

return "--$boundary$eol".implode(
"$eol--$boundary$eol",
array_merge([$statement_result], array_map(function ($attachment) use ($eol, $boundary) {
return (
$attachments = $this->statements->getAttachments($statements, $opts);
foreach ($attachments as $attachment) {
$this->emit(
"$eol--$boundary$eol".
'Content-Type:'.$attachment->content_type.$eol.
'Content-Transfer-Encoding:binary'.$eol.
'X-Experience-API-Hash:'.$attachment->hash.
$eol.$eol.
$attachment->content
$eol.$eol
);
}, $this->statements->getAttachments($statements, $opts)))
)."$eol--$boundary--";
while (!feof($attachment->content)) {
$this->emit(fread($attachment->content, 8192));
}
fclose($attachment->content);
}

$this->emit("$eol--$boundary--");
}

private function emit($value) {
echo $value;
flush();
ob_flush();
}

private function getMoreLink($count, $limit, $offset) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class AttachmentRename extends Migration {

public function up() {
$uploads = Helpers::getEnvVar('LOCAL_FILESTORE');
$uploads = Helpers::getEnvVar('FS_LOCAL_ENDPOINT');
$LRSs = $this->getDirectores($uploads);

// Gets the attachments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,56 @@
class ConsistentForeignKeyNames extends Migration {

public function up() {
$this->chunkKeyRenaming(new DocumentAPI, 'lrs', 'lrs_id');
$this->chunkKeyRenaming(new Statement, 'lrs._id', 'lrs_id');
$this->chunkKeyRenaming(new Lrs, 'owner._id', 'owner_id');
$this->chunkKeyRenaming(new Report, 'lrs', 'lrs_id');
$this->chunkKeyRenaming(new Export, 'lrs', 'lrs_id');
}

public function down() {
$this->chunkMongoIdRemoval(new DocumentAPI, 'lrs', 'lrs_id');
$this->chunkMongoIdRemoval(new Statement, 'lrs._id', 'lrs_id');
$this->chunkMongoIdRemoval(new Lrs, 'owner._id', 'owner_id');
$this->chunkMongoIdRemoval(new Report, 'lrs', 'lrs_id');
$this->chunkMongoIdRemoval(new Export, 'lrs', 'lrs_id');
}
$db = \DB::getMongoDB();

private function chunkKeyRenaming($model, $old_name, $new_name) {
$this->chunkModelMigration($model, $this->renameKey($old_name, $new_name));
}
Lrs::get()->each(function (Lrs $lrs) use ($db) {
$convertToMongoId = function ($value) {
return new \MongoId($value);
};
$this->changeForeignKey($db->statements, 'lrs._id', 'lrs_id', $lrs->_id, $convertToMongoId);
$this->changeForeignKey($db->documentapi, 'lrs', 'lrs_id', $lrs->_id, $convertToMongoId);
$this->changeForeignKey($db->reports, 'lrs', 'lrs_id', $lrs->_id, $convertToMongoId);
$this->changeForeignKey($db->exports, 'lrs', 'lrs_id', $lrs->_id, $convertToMongoId);

private function chunkMongoIdRemoval($model, $old_name, $new_name) {
$this->chunkModelMigration($model, $this->removeMongoId($old_name, $new_name));
}
$lrs->owner_id = $convertToMongoId($lrs->owner['_id']);
$lrs->save();

private function removeMongoId($old_name, $new_name) {
return function ($model) use ($old_name, $new_name) {
$value = $model->$new_name;
$model = $this->setKey($model, explode('.', $old_name), 0, (string) $value);
$model->save();
};
}
echo 'Models for "'.$lrs->title.'" converted.'.PHP_EOL;
});

private function setKey($model, $keys, $key_index, $value) {
if ($key_index < count($keys) - 1) {
$model->{$keys[$key_index]} = (object) [];
$this->setKey($model->{$keys[$key_index]}, $keys, $key_index + 1, $value);
} else {
$model->{$keys[$key_index]} = $value;
}
return $model;
}
echo 'All finished, hopefully!'.PHP_EOL;
}

private function renameKey($old_name, $new_name) {
return function ($model) use ($old_name, $new_name) {
$value = array_reduce(explode('.', $old_name), function ($value, $key) {
return is_object($value) ? $value->{$key} : $value[$key];
}, $model);
$model->$new_name = new \MongoId($value);
$model->save();
};
private function changeForeignKey($collection, $old_key, $new_key, $old_value, $modifier) {
$collection->update([
$old_key => $old_value
], [
'$set' => [
$new_key => $modifier($old_value)
]
], [
'multiple' => true
]);
}

private function chunkModelMigration($model, Callable $migration) {
$model->chunk(1000, function ($models) use ($migration) {
foreach ($models as $model){
$migration($model);
}
echo count($models) . ' converted.'.PHP_EOL;
public function down() {
$db = \DB::getMongoDB();

Lrs::get()->each(function (Lrs $lrs) use ($db) {
$convertToString = function ($value) {
return (string) $value;
};
$this->changeForeignKey($db->statements, 'lrs_id', 'lrs._id', $lrs->_id, $convertToString);
$this->changeForeignKey($db->documentapi, 'lrs_id', 'lrs', $lrs->_id, $convertToString);
$this->changeForeignKey($db->reports, 'lrs_id', 'lrs', $lrs->_id, $convertToString);
$this->changeForeignKey($db->exports, 'lrs_id', 'lrs', $lrs->_id, $convertToString);

$lrs->owner = [
'_id' => $convertToString($lrs->owner_id)
];
$lrs->save();

echo 'Models for "'.$lrs->title.'" converted.'.PHP_EOL;
});

echo 'All finished, hopefully!'.PHP_EOL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@ public function storeActivityDoc( $options, $data, $updated, $method ){

$document->updated_at = new Carbon($updated);
$document->setContent( $data['content_info'], $method ); //set the content for the document

if( $document->save() ){
return $document;
}
Expand Down
28 changes: 28 additions & 0 deletions app/locker/repository/File/Factory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php namespace Locker\Repository\File;
use Locker\Helpers\Helpers as Helpers;

class Factory {
public static function create() {
$repo = Helpers::getEnvVar('FS_REPO');

return static::createRepo($repo);
}

public static function createRepo($repo) {
$repos = [
'Local' => 'LocalFlyRepository',
'Rackspace' => 'RackspaceFlyRepository',
];
$repo = ucfirst(strtolower($repo));
$conf = function ($var) {
return Helpers::getEnvVar($var);
};

if (isset($repos[$repo])) {
$selected_repo = 'Locker\Repository\File\\'.$repos[$repo];
return new $selected_repo($conf);
} else {
throw new \Exception('Valid `FS_REPO` not specified in ".env.'.\App::environment().'.php". Valid values include: "'.implode('", "', array_keys($repos)).'". You provided "'.$repo.'".');
}
}
}
46 changes: 46 additions & 0 deletions app/locker/repository/File/FlyRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php namespace Locker\Repository\File;
use League\Flysystem\Filesystem as Filesystem;
use League\Flysystem\AdapterInterface as AdapterInterface;

abstract class FlyRepository implements Repository {
protected $filesystem;

public function __construct(Callable $conf) {}

protected function constructFileSystem(AdapterInterface $adapter) {
$this->filesystem = new Filesystem($adapter);
}

public function index(array $opts) {
return $this->filesystem->listContents('.', true);
}

public function show($id, array $opts) {
return $this->filesystem->read($id);
}

public function destroy($id, array $opts) {
$this->filesystem->delete($id);
return true;
}

public function store(array $data, array $opts) {
throw new \BadMethodCallException();
}

public function update($id, array $data, array $opts) {
$this->filesystem->put($id, $data['content']);
return $data;
}

public function stream($id, array $opts) {
$stream = $this->filesystem->readStream($id);
fseek($stream, 0);
return $stream;
}

public function has($id, array $opts) {
return $this->filesystem->has($id);
}

}
11 changes: 11 additions & 0 deletions app/locker/repository/File/LocalFlyRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php namespace Locker\Repository\File;
use League\Flysystem\Adapter\Local as LocalAdapter;

class LocalFlyRepository extends FlyRepository {

public function __construct(Callable $conf) {
$adapter = new LocalAdapter($conf('FS_LOCAL_ENDPOINT'));
$this->constructFileSystem($adapter);
}

}
Loading