Rename again to memories

Fix the migration directly because I'm the only user right now.
If this is a problem for you, drop the oc_polaroid table and the
corresponding index on the oc_filecache table.
pull/37/head
Varun Patil 2022-08-18 18:27:25 +00:00
parent dc3ea330b1
commit 0d03a9142c
22 changed files with 249 additions and 136 deletions

View File

@ -1,4 +1,4 @@
# Polaroid
# Memories
**📸 Yet another photo management app for Nextcloud**
@ -16,7 +16,7 @@
1. ☁ Clone this into your `apps` folder of your Nextcloud.
1. ⚒️ Install `exiftool` (`sudo apt install exiftool`).
1. 📸 Place all photos you want on the timeline in a folder called `Photos` (case sensitive) in the root of your home.
1. Run `php ./occ polaroid:index` to generate metadata indices for existing photos.
1. Run `php ./occ memories:index` to generate metadata indices for existing photos.
1. Consider installing the [preview generator](https://github.com/rullzer/previewgenerator) for pre-generating thumbnails.
## 🏗 Development setup

View File

@ -1,11 +1,11 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>polaroid</id>
<name>Polaroid</name>
<id>memories</id>
<name>Memories</name>
<summary>Yet another photo management app</summary>
<description><![CDATA[
# Polaroid
# Memories
* **📸 Photo and Video Timeline**: Sorts photos by date taken, parsed from Exif data.
* **🤔 Quick Recap**: Jump to anywhere in the timeline instantly.
@ -15,23 +15,23 @@
<version>0.0.1</version>
<licence>agpl</licence>
<author mail="radialapps@gmail.com" >Varun Patil</author>
<website>https://github.com/pulsejet/polaroid</website>
<bugs>https://github.com/pulsejet/polaroid/issues</bugs>
<repository>https://github.com/pulsejet/polaroid</repository>
<screenshot>https://raw.githubusercontent.com/pulsejet/polaroid/master/appinfo/screenshot.jpg</screenshot>
<namespace>Polaroid</namespace>
<website>https://github.com/pulsejet/memories</website>
<bugs>https://github.com/pulsejet/memories/issues</bugs>
<repository>https://github.com/pulsejet/memories</repository>
<screenshot>https://raw.githubusercontent.com/pulsejet/memories/master/appinfo/screenshot.jpg</screenshot>
<namespace>Memories</namespace>
<category>organization</category>
<bugs>https://github.com</bugs>
<dependencies>
<nextcloud min-version="22" max-version="24"/>
</dependencies>
<commands>
<command>OCA\Polaroid\Command\Index</command>
<command>OCA\Memories\Command\Index</command>
</commands>
<navigations>
<navigation>
<name>Polaroid</name>
<route>polaroid.page.main</route>
<name>Memories</name>
<route>memories.page.main</route>
</navigation>
</navigations>
</info>

View File

@ -1,5 +1,5 @@
{
"name": "Polaroid",
"name": "Memories",
"description": "p",
"type": "project",
"license": "AGPL",

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,145 @@
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*!
* Vue.js v2.7.8
* (c) 2014-2022 Evan You
* Released under the MIT License.
*/
/*! For license information please see AppNavigation.js.LICENSE.txt */
/*! For license information please see AppNavigationItem.js.LICENSE.txt */
/*! Hammer.JS - v2.0.7 - 2016-04-22
* http://hammerjs.github.io/
*
* Copyright (c) 2016 Jorik Tangelder;
* Licensed under the MIT license */
/*! https://mths.be/base64 v1.0.0 by @mathias | MIT license */
/*! https://mths.be/he v1.2.0 by @mathias | MIT license */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* @license nested-property https://github.com/cosmosio/nested-property
*
* The MIT License (MIT)
*
* Copyright (c) 2014-2020 Olivier Scherrer <pode.fr@gmail.com>
*/
/**!
* @fileOverview Kickass library to create and place poppers near their reference elements.
* @version 1.16.1
* @license
* Copyright (c) 2016 Federico Zivolo and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

File diff suppressed because one or more lines are too long

View File

@ -24,10 +24,10 @@ declare(strict_types=1);
*
*/
namespace OCA\Polaroid\AppInfo;
namespace OCA\Memories\AppInfo;
use OCA\Polaroid\Listeners\PostWriteListener;
use OCA\Polaroid\Listeners\PostDeleteListener;
use OCA\Memories\Listeners\PostWriteListener;
use OCA\Memories\Listeners\PostDeleteListener;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
@ -38,7 +38,7 @@ use OCP\Files\Events\Node\NodeRenamedEvent;
use OCP\Files\Events\Node\NodeTouchedEvent;
class Application extends App implements IBootstrap {
public const APPNAME = 'polaroid';
public const APPNAME = 'memories';
public const IMAGE_MIMES = [
'image/png',

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
*
*/
namespace OCA\Polaroid\Command;
namespace OCA\Memories\Command;
use OCP\Encryption\IManager;
use OCP\Files\File;
@ -58,7 +58,7 @@ class Index extends Command {
protected OutputInterface $output;
protected IManager $encryptionManager;
protected IDBConnection $connection;
protected \OCA\Polaroid\Db\Util $util;
protected \OCA\Memories\Db\Util $util;
public function __construct(IRootFolder $rootFolder,
IUserManager $userManager,
@ -75,7 +75,7 @@ class Index extends Command {
$this->config = $config;
$this->encryptionManager = $encryptionManager;
$this->connection = $connection;
$this->util = new \OCA\Polaroid\Db\Util($connection);
$this->util = new \OCA\Memories\Db\Util($connection);
try {
$this->globalService = $container->get(GlobalStoragesService::class);
@ -86,7 +86,7 @@ class Index extends Command {
protected function configure(): void {
$this
->setName('polaroid:index')
->setName('memories:index')
->setDescription('Generate entries');
}

View File

@ -23,11 +23,11 @@ declare(strict_types=1);
*
*/
namespace OCA\Polaroid\Controller;
namespace OCA\Memories\Controller;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchQuery;
use OCA\Polaroid\AppInfo\Application;
use OCA\Memories\AppInfo\Application;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
@ -45,7 +45,7 @@ class ApiController extends Controller {
private IConfig $config;
private IUserSession $userSession;
private IDBConnection $connection;
private \OCA\Polaroid\Db\Util $util;
private \OCA\Memories\Db\Util $util;
private IRootFolder $rootFolder;
public function __construct(
@ -60,7 +60,7 @@ class ApiController extends Controller {
$this->config = $config;
$this->userSession = $userSession;
$this->connection = $connection;
$this->util = new \OCA\Polaroid\Db\Util($this->connection);
$this->util = new \OCA\Memories\Db\Util($this->connection);
$this->rootFolder = $rootFolder;
}

View File

@ -1,5 +1,5 @@
<?php
namespace OCA\Polaroid\Controller;
namespace OCA\Memories\Controller;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
@ -30,7 +30,7 @@ class PageController extends Controller {
* @NoCSRFRequired
*/
public function main() {
Util::addScript($this->appName, 'polaroid-main');
Util::addScript($this->appName, 'memories-main');
Util::addStyle($this->appName, 'icons');
$this->eventDispatcher->dispatchTyped(new LoadViewer());

View File

@ -1,9 +1,9 @@
<?php
declare(strict_types=1);
namespace OCA\Polaroid\Db;
namespace OCA\Memories\Db;
use OCA\Polaroid\AppInfo\Application;
use OCA\Memories\AppInfo\Application;
use OCP\Files\File;
use OCP\IDBConnection;
@ -80,7 +80,7 @@ class Util {
// Check if need to update
$sql = 'SELECT COUNT(*) as e
FROM *PREFIX*polaroid
FROM *PREFIX*memories
WHERE file_id = ? AND user_id = ? AND mtime = ?';
$exists = $this->connection->executeQuery($sql, [
$fileId, $user, $mtime,
@ -97,7 +97,7 @@ class Util {
$dateTaken = gmdate('Y-m-d H:i:s', $dateTaken);
$sql = 'INSERT
INTO *PREFIX*polaroid (day_id, date_taken, is_video, mtime, user_id, file_id)
INTO *PREFIX*memories (day_id, date_taken, is_video, mtime, user_id, file_id)
VALUES (?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
day_id = ?, date_taken = ?, is_video = ?, mtime = ?';
@ -114,7 +114,7 @@ class Util {
public function deleteFile(File $file) {
$sql = 'DELETE
FROM *PREFIX*polaroid
FROM *PREFIX*memories
WHERE file_id = ?';
$this->connection->executeStatement($sql, [$file->getId()], [\PDO::PARAM_INT]);
}
@ -131,9 +131,9 @@ class Util {
string $user,
): array {
$sql = 'SELECT day_id, COUNT(file_id) AS count
FROM `*PREFIX*polaroid`
FROM `*PREFIX*memories`
INNER JOIN `*PREFIX*filecache`
ON `*PREFIX*filecache`.`fileid` = `*PREFIX*polaroid`.`file_id`
ON `*PREFIX*filecache`.`fileid` = `*PREFIX*memories`.`file_id`
AND `*PREFIX*filecache`.`path` LIKE "files/Photos/%"
WHERE user_id=?
GROUP BY day_id
@ -146,9 +146,9 @@ class Util {
public function getDaysFolder(int $folderId) {
$sql = 'SELECT day_id, COUNT(file_id) AS count
FROM `*PREFIX*polaroid`
FROM `*PREFIX*memories`
INNER JOIN `*PREFIX*filecache`
ON `*PREFIX*filecache`.`fileid` = `*PREFIX*polaroid`.`file_id`
ON `*PREFIX*filecache`.`fileid` = `*PREFIX*memories`.`file_id`
AND (`*PREFIX*filecache`.`parent`=? OR `*PREFIX*filecache`.`fileid`=?)
GROUP BY day_id
ORDER BY day_id DESC';
@ -174,9 +174,9 @@ class Util {
int $dayId,
): array {
$sql = 'SELECT file_id, *PREFIX*filecache.etag, is_video
FROM *PREFIX*polaroid
FROM *PREFIX*memories
INNER JOIN *PREFIX*filecache
ON *PREFIX*filecache.fileid = *PREFIX*polaroid.file_id
ON *PREFIX*filecache.fileid = *PREFIX*memories.file_id
AND `*PREFIX*filecache`.`path` LIKE "files/Photos/%"
WHERE user_id = ? AND day_id = ?
ORDER BY date_taken DESC';
@ -191,11 +191,11 @@ class Util {
int $dayId,
): array {
$sql = 'SELECT file_id, *PREFIX*filecache.etag, is_video
FROM `*PREFIX*polaroid`
FROM `*PREFIX*memories`
INNER JOIN `*PREFIX*filecache`
ON `*PREFIX*filecache`.`fileid` = `*PREFIX*polaroid`.`file_id`
ON `*PREFIX*filecache`.`fileid` = `*PREFIX*memories`.`file_id`
AND (`*PREFIX*filecache`.`parent`=? OR `*PREFIX*filecache`.`fileid`=?)
WHERE `*PREFIX*polaroid`.`day_id`=?';
WHERE `*PREFIX*memories`.`day_id`=?';
$rows = $this->connection->executeQuery($sql, [$folderId, $folderId, $dayId], [
\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT,
])->fetchAll();

View File

@ -21,7 +21,7 @@ declare(strict_types=1);
*
*/
namespace OCA\Polaroid\Listeners;
namespace OCA\Memories\Listeners;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
@ -30,10 +30,10 @@ use OCP\Files\Folder;
use OCP\IDBConnection;
class PostDeleteListener implements IEventListener {
private \OCA\Polaroid\Db\Util $util;
private \OCA\Memories\Db\Util $util;
public function __construct(IDBConnection $connection) {
$this->util = new \OCA\Polaroid\Db\Util($connection);
$this->util = new \OCA\Memories\Db\Util($connection);
}
public function handle(Event $event): void {

View File

@ -21,7 +21,7 @@ declare(strict_types=1);
*
*/
namespace OCA\Polaroid\Listeners;
namespace OCA\Memories\Listeners;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
@ -34,12 +34,12 @@ use OCP\IUserManager;
class PostWriteListener implements IEventListener {
private IUserManager $userManager;
private \OCA\Polaroid\Db\Util $util;
private \OCA\Memories\Db\Util $util;
public function __construct(IDBConnection $connection,
IUserManager $userManager) {
$this->userManager = $userManager;
$this->util = new \OCA\Polaroid\Db\Util($connection);
$this->util = new \OCA\Memories\Db\Util($connection);
}
public function handle(Event $event): void {

View File

@ -1,14 +1,38 @@
<?php
namespace OCA\Polaroid\Migration;
declare(strict_types=1);
use Closure;
use OCP\DB\Types;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
/**
* @copyright Copyright (c) 2022 Varun Patil <radialapps@gmail.com>
*
* @author Varun Patil <radialapps@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
class Version000000Date20220812163631 extends SimpleMigrationStep {
namespace OCA\Memories\Migration;
use Closure;
use OCP\DB\Types;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
class Version000000Date20220812163631 extends SimpleMigrationStep {
/**
* @param IOutput $output
@ -20,8 +44,8 @@
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if (!$schema->hasTable('polaroid')) {
$table = $schema->createTable('polaroid');
if (!$schema->hasTable('memories')) {
$table = $schema->createTable('memories');
$table->addColumn('id', 'integer', [
'autoincrement' => true,
'notnull' => true,
@ -49,14 +73,14 @@
]);
$table->setPrimaryKey(['id']);
$table->addIndex(['user_id'], 'polaroid_user_id_index');
$table->addIndex(['user_id', 'day_id'], 'polaroid_ud_index');
$table->addUniqueIndex(['user_id', 'file_id'], 'polaroid_day_uf_ui');
$table->addIndex(['user_id'], 'memories_user_id_index');
$table->addIndex(['user_id', 'day_id'], 'memories_ud_index');
$table->addUniqueIndex(['user_id', 'file_id'], 'memories_day_uf_ui');
}
if ($schema->hasTable('filecache')) {
$table = $schema->getTable('filecache');
$table->addIndex(['path'], 'polaroid_path_index');
$table->addIndex(['path'], 'memories_path_index');
}
return $schema;

4
package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "polaroid",
"name": "memories",
"version": "0.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "polaroid",
"name": "memories",
"version": "0.0.0",
"license": "agpl",
"dependencies": {

View File

@ -1,5 +1,5 @@
{
"name": "polaroid",
"name": "memories",
"description": "A better photos app",
"version": "0.0.0",
"author": "Varun Patil <radialapps@gmail.com>",
@ -13,13 +13,13 @@
"vuejs"
],
"bugs": {
"url": "https://github.com/pulsejet/polaroid/issues"
"url": "https://github.com/pulsejet/memories/issues"
},
"repository": {
"url": "https://github.com/pulsejet/polaroid.git",
"url": "https://github.com/pulsejet/memories.git",
"type": "git"
},
"homepage": "https://github.com/pulsejet/polaroid",
"homepage": "https://github.com/pulsejet/memories",
"license": "agpl",
"private": true,
"scripts": {

View File

@ -1,7 +1,7 @@
<template>
<Content app-name="polaroid">
<Content app-name="memories">
<AppNavigation>
<template id="app-polaroid-navigation" #list>
<template id="app-memories-navigation" #list>
<AppNavigationItem :to="{name: 'timeline'}"
:title="t('timeline', 'Timeline')"
icon="icon-yourphotos"

View File

@ -314,11 +314,11 @@ export default {
/** Fetch timeline main call */
async fetchDays() {
let url = '/apps/polaroid/api/days';
let url = '/apps/memories/api/days';
if (this.$route.name === 'albums') {
const id = this.$route.params.id || 0;
url = `/apps/polaroid/api/folder/${id}`;
url = `/apps/memories/api/folder/${id}`;
}
const startState = this.state;
@ -413,11 +413,11 @@ export default {
/** Fetch image data for one dayId */
async fetchDay(dayId) {
let url = `/apps/polaroid/api/days/${dayId}`;
let url = `/apps/memories/api/days/${dayId}`;
if (this.$route.name === 'albums') {
const id = this.$route.params.id || 0;
url = `/apps/polaroid/api/folder/${id}/${dayId}`;
url = `/apps/memories/api/folder/${id}/${dayId}`;
}
// Do this in advance to prevent duplicate requests

View File

@ -43,7 +43,7 @@
mode: 'history',
// if index.php is in the url AND we got this far, then it's working:
// let's keep using index.php in the url
base: generateUrl('/apps/polaroid', ''),
base: generateUrl('/apps/memories', ''),
linkActiveClass: 'active',
routes: [
{

View File

@ -1,29 +0,0 @@
<?php
namespace OCA\Polaroid\Tests\Integration\Controller;
use OCP\AppFramework\App;
use Test\TestCase;
/**
* This test shows how to make a small Integration Test. Query your class
* directly from the container, only pass in mocks if needed and run your tests
* against the database
*/
class AppTest extends TestCase {
private $container;
public function setUp() {
parent::setUp();
$app = new App('polaroid');
$this->container = $app->getContainer();
}
public function testAppInstalled() {
$appManager = $this->container->query('OCP\App\IAppManager');
$this->assertTrue($appManager->isInstalled('polaroid'));
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace OCA\Polaroid\Tests\Unit\Controller;
use PHPUnit_Framework_TestCase;
use OCP\AppFramework\Http\TemplateResponse;
use OCA\Polaroid\Controller\PageController;
class PageControllerTest extends PHPUnit_Framework_TestCase {
private $controller;
private $userId = 'john';
public function setUp() {
$request = $this->getMockBuilder('OCP\IRequest')->getMock();
$this->controller = new PageController(
'polaroid', $request, $this->userId
);
}
public function testIndex() {
$result = $this->controller->index();
$this->assertEquals('index', $result->getTemplateName());
$this->assertTrue($result instanceof TemplateResponse);
}
}

View File

@ -9,8 +9,8 @@ require_once __DIR__.'/../../../lib/base.php';
// Fix for "Autoload path not allowed: .../tests/lib/testcase.php"
\OC::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
// Fix for "Autoload path not allowed: .../polaroid/tests/testcase.php"
\OC_App::loadApp('polaroid');
// Fix for "Autoload path not allowed: .../memories/tests/testcase.php"
\OC_App::loadApp('memories');
if(!class_exists('PHPUnit_Framework_TestCase')) {
require_once('PHPUnit/Autoload.php');