This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

NEW add manage files feature

  • Loading branch information...
michalochman committed Jul 16, 2012
1 parent cd3a055 commit fbe429209eb9a698efd2f2889511f98acfbd3c1a
@@ -12,6 +12,8 @@ default:
framework_host: http://localhost
Behat\MinkExtension\Extension:
base_url: http://localhost
files_path: /Users/michal/Projects/SilverStripe/htdocs/framework/tests/behat/features/files/
# files_path: features/files/
default_session: selenium2
javascript_session: selenium2
goutte: ~
@@ -14,6 +14,8 @@
use Behat\SilverStripeExtension\Context\SilverStripeAwareContextInterface;
use Symfony\Component\Yaml\Yaml;
// Mink etc.
require_once 'vendor/autoload.php';
@@ -28,6 +30,9 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
protected $context;
protected $fixtures;
protected $fixtures_lazy;
protected $files_path;
protected $created_files_paths;
/**
* Initializes context.
@@ -102,11 +107,20 @@ public function after(ScenarioEvent $event)
/**
* @Given /^there are the following ([^\s]*) records$/
*/
public function thereAreTheFollowingPermissionRecords($data_object, PyStringNode $string)
public function thereAreTheFollowingRecords($data_object, PyStringNode $string)
{
if (!is_array($this->fixtures)) {
$this->fixtures = array();
}
if (!is_array($this->fixtures_lazy)) {
$this->fixtures_lazy = array();
}
if (!isset($this->files_path)) {
$this->files_path = realpath($this->getMinkParameter('files_path'));
}
if (!is_array($this->created_files_paths)) {
$this->created_files_paths = array();
}
if (array_key_exists($data_object, $this->fixtures)) {
throw new \InvalidArgumentException(sprintf('Data object `%s` already exists!', $data_object));
@@ -115,15 +129,107 @@ public function thereAreTheFollowingPermissionRecords($data_object, PyStringNode
$fixture = array_merge(array($data_object . ':'), $string->getLines());
$fixture = implode("\n ", $fixture);
// As we're dealing with split fixtures and can't join them, replace references by hand
$fixture = preg_replace_callback('/=>(\w+)\.(\w+)/', array($this, 'replaceFixtureReferences'), $fixture);
if ('Folder' === $data_object) {
$this->prepareTestAssetsDirectories($fixture);
}
if ('File' === $data_object) {
$this->prepareTestAssetsFiles($fixture);
}
$fixtures_lazy = array($data_object => array());
if (preg_match('/=>(\w+)/', $fixture)) {
$fixture_content = Yaml::parse($fixture);
foreach ($fixture_content[$data_object] as $identifier => &$fields) {
foreach ($fields as $field_val) {
if (substr($field_val, 0, 2) == '=>') {
$fixtures_lazy[$data_object][$identifier] = $fixture_content[$data_object][$identifier];
unset($fixture_content[$data_object][$identifier]);
}
}
}
$fixture = Yaml::dump($fixture_content);
}
// As we're dealing with split fixtures and can't join them, replace references by hand
// if (preg_match('/=>(\w+)\.([\w.]+)/', $fixture, $matches)) {
// if ($matches[1] !== $data_object) {
// $fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture);
// }
// }
$fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture);
// Save fixtures into database
$this->fixtures[$data_object] = new \YamlFixture($fixture);
$model = \DataModel::inst();
$this->fixtures[$data_object]->saveIntoDatabase($model);
// Lazy load fixtures into database
// Loop is required for nested lazy fixtures
foreach ($fixtures_lazy[$data_object] as $identifier => $fields) {
$fixture = array(
$data_object => array(
$identifier => $fields,
),
);
$fixture = Yaml::dump($fixture);
$fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture);
$this->fixtures_lazy[$data_object][$identifier] = new \YamlFixture($fixture);
$this->fixtures_lazy[$data_object][$identifier]->saveIntoDatabase($model);
}
}
public function replaceFixtureReferences($references)
protected function prepareTestAssetsDirectories($fixture)
{
$folders = Yaml::parse($fixture);
foreach ($folders['Folder'] as $fields) {
foreach ($fields as $field => $value) {

This comment has been minimized.

@michalochman

michalochman Jul 17, 2012

Owner

I think I will drop this loop and just check for the "Filename" field here.

if ('Filename' === $field) {
if (0 === strpos($value, 'assets/')) {
$value = substr($value, strlen('assets/'));
}
$folder_path = ASSETS_PATH . DIRECTORY_SEPARATOR . $value;
if (file_exists($folder_path) && !is_dir($folder_path)) {
throw new \Exception(sprintf('`%s` already exists and is not a directory', $this->files_path));
}
if (@mkdir($folder_path, 0777, true)) {

This comment has been minimized.

@chillu

chillu Jul 17, 2012

Contributor

Creating with 777 might fail, depending on permissions of the CLI/webserver user. Try Filesystem::makeFolder()

This comment has been minimized.

@michalochman

michalochman Jul 17, 2012

Owner

0777 is default setting. It is masked with umask anyway.

$this->created_files_paths[] = $folder_path;
}
}
}
}
}
protected function prepareTestAssetsFiles($fixture)
{
$files = Yaml::parse($fixture);
foreach ($files['File'] as $fields) {
foreach ($fields as $field => $value) {
if ('Filename' === $field) {
if (0 === strpos($value, 'assets/')) {
$value = substr($value, strlen('assets/'));
}
$file_path = $this->files_path . DIRECTORY_SEPARATOR . basename($value);
if (!file_exists($file_path) || !is_file($file_path)) {
throw new \Exception(sprintf('`%s` does not exist or is not a file', $this->files_path));
}
$asset_path = ASSETS_PATH . DIRECTORY_SEPARATOR . $value;
if (file_exists($asset_path) && !is_file($asset_path)) {
throw new \Exception(sprintf('`%s` already exists and is not a file', $this->files_path));
}
if (!file_exists($asset_path)) {
if (@copy($file_path, $asset_path)) {
$this->created_files_paths[] = $asset_path;
}
}
}
}
}
}
protected function replaceFixtureReferences($references)
{
if (!array_key_exists($references[1], $this->fixtures)) {
throw new \OutOfBoundsException(sprintf('Data object `%s` does not exist!', $references[1]));
@@ -133,7 +239,15 @@ public function replaceFixtureReferences($references)
protected function idFromFixture($class_name, $identifier)
{
return $this->fixtures[$class_name]->idFromFixture($class_name, $identifier);
if (false !== ($id = $this->fixtures[$class_name]->idFromFixture($class_name, $identifier))) {
return $id;
}
if (isset($this->fixtures_lazy[$class_name], $this->fixtures_lazy[$class_name][$identifier]) &&
false !== ($id = $this->fixtures_lazy[$class_name][$identifier]->idFromFixture($class_name, $identifier))) {
return $id;
}
throw new \OutOfBoundsException(sprintf('`%s` identifier in Data object `%s` does not exist!', $identifier, $class_name));
}
/**
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,100 @@
@javascript
Feature: Manage files
As a cms author
I want to upload and manage files within the CMS
So that I can insert them into my content efficiently
Background:
# Unfortunately, we need this duplication of "Parent" relationship
# and specifying the path via "Filename".
#
# Idea: We could weave the database reset into this through
# saying 'Given there are ONLY the following...'.
Given there are the following Folder records
"""
folder1:
Filename: assets/folder1
folder1.1:
Filename: assets/folder1/folder1.1
Parent: =>Folder.folder1
folder2:
Filename: assets/folder2
Name: folder2
"""
# Will need to copy the files from "files_path" into the assets/ folder.
# Should be part of the fixture logic, with a special case for "File"
And there are the following File records
"""
file1:
Filename: assets/folder1/file1.jpg
Name: file1.jpg
Parent: =>Folder.folder1
file2:
Filename: assets/folder1/folder1.1/file2.jpg
Name: file2.jpg
Parent: =>Folder.folder1.1
"""
And I am logged in with "ADMIN" permissions
# Alternative fixture shortcuts, with their titles
# as shown in admin/security rather than technical permission codes.
# Just an idea for now, could be handled by YAML fixtures as well
# And I am logged in with the following permissions
# - Access to 'Pages' section
# - Access to 'Files' section
And I go to "/admin/assets"
Scenario: I can add a new folder
Given I press "Add folder" button
And I type "newfolder" into the dialog
And I confirm the dialog
Then I should see "newfolder" in the CMS edit area
Scenario: I can list files in a folder
# Slight variation of the "in the '#<selector>' area, specific for GridFields with a title
Given I click on "folder1" in the "Files" table
# Maybe we can make these composite steps,
# so have the "... in the 'folder1' table" separate?
Then the "folder1" table should contain "file1"
# Means the previous match has to be exact rather than partial.
# I think thats a good idea to avoid false positives.
# Also: I bet there's a smart way in Behat to handle negations like this.
And the "folder1" table should not contain "file1.1"
# Requires 'files_path' being set up for Mink,
# see http://extensions.behat.org/mink/index.html#usage
Scenario: I can upload a file to a folder
Given I click on "folder1" in the "Files" table
And I press "Upload" button
And I attach the file "testfile.jpg" to "AssetUploadField"
# Good enough for now, unless you can find an easy way
# to check for both HTML5 uploads and hidden iframes.
# We use https://github.com/blueimp/jQuery-File-Upload for this.
And I wait for "30000"
And I press "Back to folder" button
Then the "Files" table should contain "testfile.jpg"
Scenario: I can edit a file
Given I click on "folder1" in the "Files" table
And I click on "file1" in the "folder1" table
And I fill in "renamedfile" for "Title"
And I press "Save" button
And I press "Back" button
Then the "folder1" table should not contain "testfile"
And the "folder1" table should contain "renamedfile"
Scenario: I can delete a file
Given I click on "folder1" in the "Files" table
# Note that the file name in DB and filesystem should be reset from the
# previous scenario at this point
And I click on "file1" in the "folder1" table
And I press "Delete" button
Scenario: I can change the folder of a file
Given I click on "folder1" in the "Files" table
And I click on "file1.jpg" in the "folder1" table
# Should be implemented as a generic preprocessor available to all steps
And I fill in "=>Folder.folder2.ID" for "ParentID"
And I press the "Save" button
And I go to "/admin/assets"
And I click on "folder2" in the "Files" table
And the "folder2" table should contain "file1.jpg"

2 comments on commit fbe4292

@michalochman

This comment has been minimized.

Owner

michalochman replied Jul 16, 2012

Have to add code to delete files and directories providing they were created during the process from assets directory, hence $created_files_paths.

@michalochman

This comment has been minimized.

Owner

michalochman replied Jul 16, 2012

L1R#155-L1R#159 should be enough for YamlFixture lazy fixtures to work, but apparently it isn't – need to investigate.

Please sign in to comment.