Upgraded to Laravel 5.4

This commit is contained in:
An Phan 2017-02-14 14:53:02 +08:00
parent 38862270db
commit bdca871b6e
No known key found for this signature in database
GPG key ID: 05536BB4BCDC02A2
97 changed files with 3425 additions and 4141 deletions

View file

@ -104,5 +104,5 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=null
PUSHER_APP_ID= PUSHER_APP_ID=
PUSHER_KEY= PUSHER_APP_KEY=
PUSHER_SECRET= PUSHER_APP_SECRET=

View file

@ -45,14 +45,16 @@ class Application extends IlluminateApplication
{ {
static $manifest = null; static $manifest = null;
$manifestFile = $manifestFile ?: $this->publicPath().'/public/build/rev-manifest.json'; $manifestFile = $manifestFile ?: public_path('public/mix-manifest.json');
if ($manifest === null) { if ($manifest === null) {
$manifest = json_decode(file_get_contents($manifestFile), true); $manifest = json_decode(file_get_contents($manifestFile), true);
} }
if (isset($manifest[$file])) { if (isset($manifest[$file])) {
return $this->staticUrl("public/build/{$manifest[$file]}"); return file_exists(public_path('public/hot'))
? "http://localhost:8080{$manifest[$file]}"
: $this->staticUrl("public{$manifest[$file]}");
} }
throw new InvalidArgumentException("File {$file} not defined in asset manifest."); throw new InvalidArgumentException("File {$file} not defined in asset manifest.");

View file

@ -5,12 +5,15 @@ namespace App\Http;
use App\Http\Middleware\Authenticate; use App\Http\Middleware\Authenticate;
use App\Http\Middleware\GetUserFromToken; use App\Http\Middleware\GetUserFromToken;
use App\Http\Middleware\ObjectStorageAuthenticate; use App\Http\Middleware\ObjectStorageAuthenticate;
use App\Http\Middleware\TrimStrings;
use App\Http\Middleware\UseDifferentConfigIfE2E; use App\Http\Middleware\UseDifferentConfigIfE2E;
use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode; use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
class Kernel extends HttpKernel class Kernel extends HttpKernel
{ {
@ -22,6 +25,9 @@ class Kernel extends HttpKernel
protected $middleware = [ protected $middleware = [
CheckForMaintenanceMode::class, CheckForMaintenanceMode::class,
UseDifferentConfigIfE2E::class, UseDifferentConfigIfE2E::class,
ValidatePostSize::class,
TrimStrings::class,
ConvertEmptyStringsToNull::class,
]; ];
/** /**

View file

@ -3,8 +3,8 @@
namespace App\Http\Middleware; namespace App\Http\Middleware;
use App\JWTAuth; use App\JWTAuth;
use Illuminate\Events\Dispatcher; use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Routing\ResponseFactory; use Illuminate\Contracts\Routing\ResponseFactory;
use Tymon\JWTAuth\Middleware\BaseMiddleware as JWTBaseMiddleware; use Tymon\JWTAuth\Middleware\BaseMiddleware as JWTBaseMiddleware;
abstract class BaseMiddleware extends JWTBaseMiddleware abstract class BaseMiddleware extends JWTBaseMiddleware

View file

@ -0,0 +1,18 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as BaseTrimmer;
class TrimStrings extends BaseTrimmer
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
];
}

View file

@ -15,7 +15,7 @@ class JWTAuth extends BaseJWTAuth
*/ */
public function __construct(JWTManager $manager, UserInterface $user, AuthInterface $auth, Request $request) public function __construct(JWTManager $manager, UserInterface $user, AuthInterface $auth, Request $request)
{ {
return parent::__construct($manager, $user, $auth, $request); parent::__construct($manager, $user, $auth, $request);
} }
/** /**

View file

@ -16,11 +16,6 @@ class BroadcastServiceProvider extends ServiceProvider
{ {
Broadcast::routes(); Broadcast::routes();
/* require base_path('routes/channels.php');
* Authenticate the user's personal channel...
*/
Broadcast::channel('App.User.*', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
} }
} }

View file

@ -47,12 +47,9 @@ class RouteServiceProvider extends ServiceProvider
*/ */
protected function mapWebRoutes() protected function mapWebRoutes()
{ {
Route::group([ Route::middleware('web')
'middleware' => 'web', ->namespace($this->namespace)
'namespace' => $this->namespace, ->group(base_path('routes/web.php'));
], function ($router) {
require base_path('routes/web.php');
});
} }
/** /**
@ -64,12 +61,9 @@ class RouteServiceProvider extends ServiceProvider
*/ */
protected function mapApiRoutes() protected function mapApiRoutes()
{ {
Route::group([ Route::prefix('api')
'middleware' => 'api', ->middleware('api')
'namespace' => $this->namespace, ->namespace($this->namespace)
'prefix' => 'api', ->group(base_path('routes/api.php'));
], function ($router) {
require base_path('routes/api.php');
});
} }
} }

View file

@ -15,20 +15,3 @@ define('LARAVEL_START', microtime(true));
*/ */
require __DIR__.'/../vendor/autoload.php'; require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Include The Compiled Class File
|--------------------------------------------------------------------------
|
| To dramatically increase your application's performance, you may use a
| compiled class file which contains all of the classes commonly used
| by a request. The Artisan "optimize" is used to create this file.
|
*/
$compiledPath = __DIR__.'/cache/compiled.php';
if (file_exists($compiledPath)) {
require $compiledPath;
}

View file

@ -6,7 +6,7 @@
"type": "project", "type": "project",
"require": { "require": {
"php": ">=5.6.4", "php": ">=5.6.4",
"laravel/framework": "5.3.*", "laravel/framework": "5.4.*",
"james-heinrich/getid3": "^1.9", "james-heinrich/getid3": "^1.9",
"guzzlehttp/guzzle": "^6.1", "guzzlehttp/guzzle": "^6.1",
"tymon/jwt-auth": "^0.5.6", "tymon/jwt-auth": "^0.5.6",
@ -17,24 +17,27 @@
"require-dev": { "require-dev": {
"fzaninotto/faker": "~1.4", "fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*", "mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0", "phpunit/phpunit": "~5.7",
"phpspec/phpspec": "~2.1",
"symfony/css-selector": "2.8.*|3.0.*", "symfony/css-selector": "2.8.*|3.0.*",
"symfony/dom-crawler": "2.8.*|3.0.*", "symfony/dom-crawler": "^3.2",
"facebook/webdriver": "^1.2", "facebook/webdriver": "^1.2",
"barryvdh/laravel-ide-helper": "^2.1" "barryvdh/laravel-ide-helper": "^2.1",
"laravel/tinker": "^1.0",
"laravel/browser-kit-testing": "^1.0"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
"database" "database"
], ],
"psr-4": { "psr-4": {
"App\\": "app/" "App\\": "app/",
"Tests\\": "tests/"
} }
}, },
"autoload-dev": { "autoload-dev": {
"classmap": [ "classmap": [
"tests/TestCase.php", "tests/TestCase.php",
"tests/BrowserKitTestCase.php",
"tests/e2e" "tests/e2e"
] ]
}, },

1777
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -138,7 +138,7 @@ return [
Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class, Illuminate\View\ViewServiceProvider::class,
Laravel\Tinker\TinkerServiceProvider::class,
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class, Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
Aws\Laravel\AwsServiceProvider::class, Aws\Laravel\AwsServiceProvider::class,

View file

@ -30,8 +30,8 @@ return [
'pusher' => [ 'pusher' => [
'driver' => 'pusher', 'driver' => 'pusher',
'key' => env('PUSHER_KEY'), 'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_SECRET'), 'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'), 'app_id' => env('PUSHER_APP_ID'),
'options' => [ 'options' => [
// //

View file

@ -44,7 +44,7 @@ return [
'file' => [ 'file' => [
'driver' => 'file', 'driver' => 'file',
'path' => storage_path('framework/cache'), 'path' => storage_path('framework/cache/data'),
], ],
'memcached' => [ 'memcached' => [

View file

@ -2,19 +2,6 @@
return [ return [
/*
|--------------------------------------------------------------------------
| PDO Fetch Style
|--------------------------------------------------------------------------
|
| By default, database results will be returned as instances of the PHP
| stdClass object; however, you may desire to retrieve records in an
| array format for simplicity. Here you can tweak the fetch style.
|
*/
'fetch' => PDO::FETCH_CLASS,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Database Connection Name | Default Database Connection Name
@ -64,8 +51,8 @@ return [
'database' => env('DB_DATABASE', 'forge'), 'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'), 'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''), 'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8', 'charset' => 'utf8mb4',
'collation' => 'utf8_unicode_ci', 'collation' => 'utf8mb4_unicode_ci',
'prefix' => '', 'prefix' => '',
'strict' => false, 'strict' => false,
], ],
@ -119,13 +106,22 @@ return [
'redis' => [ 'redis' => [
'cluster' => false, 'client' => 'predis',
'options' => [
'cluster' => 'redis',
],
'clusters' => [
'default' => [ 'default' => [
'host' => '127.0.0.1', [
'port' => 6379, 'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0, 'database' => 0,
], ],
],
],
], ],

View file

@ -64,10 +64,10 @@ return [
's3' => [ 's3' => [
'driver' => 's3', 'driver' => 's3',
'key' => 'your-key', 'key' => env('AWS_KEY'),
'secret' => 'your-secret', 'secret' => env('AWS_SECRET'),
'region' => 'your-region', 'region' => env('AWS_REGION'),
'bucket' => 'your-bucket', 'bucket' => env('AWS_BUCKET'),
], ],
'rackspace' => [ 'rackspace' => [

View file

@ -1,7 +1,5 @@
<?php <?php
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Mail Driver | Mail Driver
@ -11,12 +9,11 @@ return [
| sending of e-mail. You may specify which one you're using throughout | sending of e-mail. You may specify which one you're using throughout
| your application here. By default, Laravel is setup for SMTP mail. | your application here. By default, Laravel is setup for SMTP mail.
| |
| Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", "ses", "log" | Supported: "smtp", "sendmail", "mailgun", "mandrill", "ses",
| "sparkpost", "log", "array"
| |
*/ */
'driver' => env('MAIL_DRIVER', 'smtp'), 'driver' => env('MAIL_DRIVER', 'smtp'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| SMTP Host Address | SMTP Host Address
@ -27,9 +24,7 @@ return [
| the Mailgun mail service which will provide reliable deliveries. | the Mailgun mail service which will provide reliable deliveries.
| |
*/ */
'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| SMTP Host Port | SMTP Host Port
@ -40,9 +35,7 @@ return [
| stay compatible with the Mailgun e-mail application by default. | stay compatible with the Mailgun e-mail application by default.
| |
*/ */
'port' => env('MAIL_PORT', 587), 'port' => env('MAIL_PORT', 587),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Global "From" Address | Global "From" Address
@ -53,9 +46,10 @@ return [
| used globally for all e-mails that are sent by your application. | used globally for all e-mails that are sent by your application.
| |
*/ */
'from' => [
'from' => ['address' => null, 'name' => null], 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| E-Mail Encryption Protocol | E-Mail Encryption Protocol
@ -66,9 +60,7 @@ return [
| transport layer security protocol should provide great security. | transport layer security protocol should provide great security.
| |
*/ */
'encryption' => env('MAIL_ENCRYPTION', 'tls'), 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| SMTP Server Username | SMTP Server Username
@ -79,22 +71,8 @@ return [
| connection. You may also set the "password" value below this one. | connection. You may also set the "password" value below this one.
| |
*/ */
'username' => env('MAIL_USERNAME'), 'username' => env('MAIL_USERNAME'),
/*
|--------------------------------------------------------------------------
| SMTP Server Password
|--------------------------------------------------------------------------
|
| Here you may set the password required by your SMTP server to send out
| messages from your application. This will be given to the server on
| connection so that the application will be able to send messages.
|
*/
'password' => env('MAIL_PASSWORD'), 'password' => env('MAIL_PASSWORD'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Sendmail System Path | Sendmail System Path
@ -105,7 +83,21 @@ return [
| been provided here, which will work well on most of your systems. | been provided here, which will work well on most of your systems.
| |
*/ */
'sendmail' => '/usr/sbin/sendmail -bs', 'sendmail' => '/usr/sbin/sendmail -bs',
/*
|--------------------------------------------------------------------------
| Markdown Mail Settings
|--------------------------------------------------------------------------
|
| If you are using Markdown based email rendering, you may configure your
| theme and component paths here, allowing you to customize the design
| of the emails. Or, you may simply stick with the Laravel defaults!
|
*/
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
]; ];

View file

@ -14,8 +14,7 @@
"url": "https://github.com/phanan/koel" "url": "https://github.com/phanan/koel"
}, },
"babel": { "babel": {
"presets": ["es2015"], "presets": ["es2015"]
"plugins": ["lodash"]
}, },
"eslintConfig": { "eslintConfig": {
"extends": "vue", "extends": "vue",
@ -27,15 +26,13 @@
"alertify.js": "^1.0.12", "alertify.js": "^1.0.12",
"axios": "^0.15.3", "axios": "^0.15.3",
"blueimp-md5": "^2.3.0", "blueimp-md5": "^2.3.0",
"font-awesome": "^4.5.0",
"intersection-observer": "^0.2.0", "intersection-observer": "^0.2.0",
"ismobilejs": "^0.4.0", "ismobilejs": "^0.4.0",
"local-storage": "^1.4.2", "local-storage": "^1.4.2",
"lodash": "^4.6.1", "lodash": "^4.16.2",
"nouislider": "^9.1.0", "nouislider": "^9.1.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"plyr": "1.5.x", "plyr": "1.5.x",
"raven-js": "^3.9.1",
"select": "^1.0.6", "select": "^1.0.6",
"slugify": "^1.0.2", "slugify": "^1.0.2",
"vue": "^2.1.9", "vue": "^2.1.9",
@ -44,37 +41,30 @@
"youtube-player": "^3.0.4" "youtube-player": "^3.0.4"
}, },
"devDependencies": { "devDependencies": {
"babel-plugin-lodash": "^2.2.1", "autoprefixer": "^6.7.2",
"babel-plugin-transform-runtime": "^6.3.13", "babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.9.1", "babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.3.13", "babel-register": "^6.23.0",
"babel-preset-react": "^6.3.13", "babel-runtime": "^6.22.0",
"babel-register": "^6.3.13",
"babel-runtime": "^6.0.0",
"browserify-hmr": "^0.3.1",
"chai": "^3.4.1", "chai": "^3.4.1",
"chalk": "^1.1.3", "chalk": "^1.1.3",
"cross-env": "^1.0.7", "cross-env": "^3.1.4",
"eslint": "^3.10.2", "eslint": "^3.10.2",
"eslint-config-vue": "^2.0.1", "eslint-config-vue": "^2.0.1",
"eslint-plugin-vue": "^1.0.0", "eslint-plugin-vue": "^1.0.0",
"gulp": "^3.9.0", "font-awesome": "^4.7.0",
"gulp-util": "^3.0.7",
"jsdom": "^9.2.1", "jsdom": "^9.2.1",
"laravel-elixir": "^5.0.0", "laravel-mix": "^0.7.4",
"mocha": "^2.3.4", "mocha": "^2.3.4",
"node-sass": "^3.4.2", "node-sass": "^3.4.2",
"postcss-cssnext": "^2.6.0", "sinon": "^1.17.2"
"sinon": "^1.17.2",
"vue-hot-reload-api": "^1.3.2",
"vueify": "^9.1.0",
"vueify-insert-css": "^1.0.0"
}, },
"scripts": { "scripts": {
"postinstall": "cross-env NODE_ENV=production && gulp --production", "postinstall": "yarn build",
"build": "cross-env NODE_ENV=production && gulp --production",
"test": "eslint resources/assets/js --ext=js,vue && mocha --compilers js:babel-register --require resources/assets/js/tests/helper.js resources/assets/js/tests/**/*Test.js", "test": "eslint resources/assets/js --ext=js,vue && mocha --compilers js:babel-register --require resources/assets/js/tests/helper.js resources/assets/js/tests/**/*Test.js",
"e2e": "gulp e2e", "dev": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules",
"dev": "cross-env NODE_ENV=development && gulp watch" "watch": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules",
"hot": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot",
"build": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules"
} }
} }

View file

@ -1,5 +0,0 @@
suites:
main:
namespace: App
psr4_prefix: App
src_path: app

View file

@ -9,14 +9,17 @@
processIsolation="false" processIsolation="false"
stopOnFailure="false"> stopOnFailure="false">
<testsuites> <testsuites>
<testsuite name="Application Test Suite"> <testsuite name="Feature Tests">
<directory>./tests/</directory> <directory suffix="Test.php">./tests/Feature</directory>
<exclude>./tests/e2e</exclude> </testsuite>
<testsuite name="Unit Tests">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter> <filter>
<whitelist> <whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">app/</directory> <directory suffix=".php">./app/</directory>
</whitelist> </whitelist>
</filter> </filter>
<php> <php>

View file

@ -1,10 +1,8 @@
require('intersection-observer') import './static-loader'
import Vue from 'vue' import Vue from 'vue'
import { VirtualScroller } from 'vue-virtual-scroller'
import { event } from './utils' import { event } from './utils'
import { http } from './services' import { http } from './services'
import { VirtualScroller } from 'vue-virtual-scroller/dist/vue-virtual-scroller'
Vue.component('virtual-scroller', VirtualScroller) Vue.component('virtual-scroller', VirtualScroller)
/** /**

View file

@ -229,7 +229,7 @@ Vue.directive('koel-focus', focusDirective)
Vue.directive('koel-clickaway', clickawayDirective) Vue.directive('koel-clickaway', clickawayDirective)
</script> </script>
<style lang="sass"> <style lang="scss">
@import "resources/assets/sass/partials/_vars.scss"; @import "resources/assets/sass/partials/_vars.scss";
@import "resources/assets/sass/partials/_mixins.scss"; @import "resources/assets/sass/partials/_mixins.scss";
@import "resources/assets/sass/partials/_shared.scss"; @import "resources/assets/sass/partials/_shared.scss";

View file

@ -38,7 +38,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";
@import "../../../sass/partials/_shared.scss"; @import "../../../sass/partials/_shared.scss";

View file

@ -88,7 +88,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -71,7 +71,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -116,7 +116,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -13,7 +13,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";
</style> </style>

View file

@ -56,7 +56,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
#youtube-extra-wrapper { #youtube-extra-wrapper {
overflow-x: hidden; overflow-x: hidden;

View file

@ -16,7 +16,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -147,7 +147,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -63,7 +63,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -139,7 +139,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -65,7 +65,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -65,7 +65,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -154,7 +154,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -68,7 +68,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -128,7 +128,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -180,7 +180,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -81,7 +81,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -84,7 +84,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -42,7 +42,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";
</style> </style>

View file

@ -64,7 +64,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -56,7 +56,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -149,7 +149,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -155,7 +155,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -58,7 +58,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../../sass/partials/_vars.scss"; @import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss"; @import "../../../../sass/partials/_mixins.scss";

View file

@ -322,7 +322,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -79,7 +79,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -102,7 +102,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -91,7 +91,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -55,7 +55,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -80,7 +80,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -141,7 +141,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -26,7 +26,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -104,4 +104,4 @@ export default {
} }
</script> </script>
<style lang="sass"></style> <style lang="scss"></style>

View file

@ -433,7 +433,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -175,7 +175,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -45,7 +45,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
.bars { .bars {
width: 28px; width: 28px;
height: 13px; height: 13px;

View file

@ -35,7 +35,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -54,7 +54,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
a.view-on-itunes { a.view-on-itunes {
display: inline-block; display: inline-block;
border-radius: 3px; border-radius: 3px;

View file

@ -155,7 +155,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -73,7 +73,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";
</style> </style>

View file

@ -59,7 +59,7 @@ export default {
} }
</script> </script>
<style lang="sass" scoped> <style lang="scss" scoped>
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -224,7 +224,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -198,7 +198,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -36,7 +36,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -46,7 +46,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -43,7 +43,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -30,7 +30,7 @@ export default {
} }
</script> </script>
<style lang="sass"> <style lang="scss">
@import "../../../sass/partials/_vars.scss"; @import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss"; @import "../../../sass/partials/_mixins.scss";

View file

@ -0,0 +1,7 @@
import 'babel-polyfill/dist/polyfill.min.js'
import 'plyr/dist/plyr.js'
import './libs/modernizr-custom.js'
import '../css/meyer-reset.min.css'
import 'nouislider/distribute/nouislider.min.css'
import 'intersection-observer'
import 'font-awesome/css/font-awesome.min.css'

View file

@ -17,14 +17,12 @@
<link rel="icon" href="{{ App::staticUrl('public/img/icon.png') }}"> <link rel="icon" href="{{ App::staticUrl('public/img/icon.png') }}">
<link rel="apple-touch-icon" href="{{ App::staticUrl('public/img/icon.png') }}"> <link rel="apple-touch-icon" href="{{ App::staticUrl('public/img/icon.png') }}">
<link rel="stylesheet" href="{{ App::rev('css/vendors.css') }}"> <link rel="stylesheet" href="{{ App::rev('/css/app.css') }}">
<link rel="stylesheet" href="{{ App::rev('css/app.css') }}">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<noscript>It may sound funny, but Koel requires JavaScript to sing. Please enable it.</noscript> <noscript>It may sound funny, but Koel requires JavaScript to sing. Please enable it.</noscript>
<script src="{{ App::rev('js/vendors.js') }}"></script> <script src="{{ App::rev('/js/app.js') }}"></script>
<script src="{{ App::rev('js/main.js') }}"></script>
</body> </body>
</html> </html>

17
routes/channels.php Normal file
View file

@ -0,0 +1,17 @@
<?php
use Illuminate\Support\Facades\Broadcast;
/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/
Broadcast::channel('App.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});

View file

@ -1,47 +0,0 @@
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
class ApplicationTest extends TestCase
{
public function testStaticUrlWithoutCDN()
{
config(['koel.cdn.url' => '']);
$this->assertEquals(App::staticUrl(), 'http://localhost/');
$this->assertEquals(App::staticUrl('foo.css '), 'http://localhost/foo.css');
}
public function testStaticUrlWithCDN()
{
config(['koel.cdn.url' => 'http://cdn.bar']);
$this->assertEquals(App::staticUrl(), 'http://cdn.bar/');
$this->assertEquals(App::staticUrl('foo.css '), 'http://cdn.bar/foo.css');
}
public function testRev()
{
config(['koel.cdn.url' => '']);
$manifestFile = __DIR__.'/blobs/rev-manifest.json';
$this->assertEquals(App::rev('foo.css', $manifestFile), 'http://localhost/public/build/foo00.css');
config(['koel.cdn.url' => 'http://cdn.bar']);
$this->assertEquals(App::rev('bar.js', $manifestFile), 'http://cdn.bar/public/build/bar00.js');
}
public function testGetLatestVersion()
{
$mock = new MockHandler([
new Response(200, [], file_get_contents(__DIR__.'/blobs/github-tags.json')),
]);
$client = new Client(['handler' => HandlerStack::create($mock)]);
$this->assertEquals('v1.1.2', App::getLatestVersion($client));
}
}

View file

@ -0,0 +1,131 @@
<?php
namespace Tests;
use App\Models\Album;
use App\Models\Artist;
use App\Models\Song;
use App\Models\User;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use JWTAuth;
use Laravel\BrowserKitTesting\TestCase as BaseBrowserKitTestCase;
abstract class BrowserKitTestCase extends BaseBrowserKitTestCase
{
protected $mediaPath;
protected $coverPath;
public function __construct()
{
parent::__construct();
$this->mediaPath = __DIR__.'/songs';
}
public function setUp()
{
parent::setUp();
$this->prepareForTests();
}
/**
* The base URL to use while testing the application.
*
* @var string
*/
protected $baseUrl = 'http://localhost';
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$this->coverPath = $app->basePath().'/public/img/covers';
return $app;
}
private function prepareForTests()
{
Artisan::call('migrate');
if (!User::all()->count()) {
Artisan::call('db:seed');
}
if (!file_exists($this->coverPath)) {
mkdir($this->coverPath, 0777, true);
}
}
/**
* Create a sample media set, with a complete artist+album+song trio.
*/
protected function createSampleMediaSet()
{
$artist = factory(Artist::class)->create();
// Sample 3 albums
$albums = factory(Album::class, 3)->create([
'artist_id' => $artist->id,
]);
// 7-15 songs per albums
foreach ($albums as $album) {
factory(Song::class, random_int(7, 15))->create([
'album_id' => $album->id,
]);
}
}
protected function getAsUser($url, $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->get($url, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
protected function deleteAsUser($url, $data = [], $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->delete($url, $data, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
protected function postAsUser($url, $data, $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->post($url, $data, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
protected function putAsUser($url, $data, $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->put($url, $data, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
trait CreatesApplication
{
protected $coverPath;
/**
* The base URL to use while testing the application.
*
* @var string
*/
protected $baseUrl = 'http://localhost';
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$this->coverPath = $app->basePath().'/public/img/covers';
return $app;
}
}

View file

@ -0,0 +1,57 @@
<?php
namespace Tests\Feature;
use App;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use Tests\BrowserKitTestCase;
class ApplicationTest extends BrowserKitTestCase
{
public function setUp()
{
parent::setUp();
@unlink(App::publicPath().'/public/hot');
}
public function testStaticUrlWithoutCDN()
{
config(['koel.cdn.url' => '']);
$this->assertEquals('http://localhost/', App::staticUrl());
$this->assertEquals('http://localhost/foo.css', App::staticUrl('/foo.css '));
}
public function testStaticUrlWithCDN()
{
config(['koel.cdn.url' => 'http://cdn.bar']);
$this->assertEquals('http://cdn.bar/', App::staticUrl());
$this->assertEquals('http://cdn.bar/foo.css', App::staticUrl('/foo.css '));
}
public function testRev()
{
config(['koel.cdn.url' => '']);
$manifestFile = __DIR__.'../../blobs/rev-manifest.json';
$this->assertEquals('http://localhost/public/foo00.css', App::rev('/foo.css', $manifestFile));
config(['koel.cdn.url' => 'http://cdn.bar']);
$this->assertEquals('http://cdn.bar/public/bar00.js', App::rev('/bar.js', $manifestFile));
}
public function testGetLatestVersion()
{
$mock = new MockHandler([
new Response(200, [], file_get_contents(__DIR__.'../../blobs/github-tags.json')),
]);
$client = new Client(['handler' => HandlerStack::create($mock)]);
$this->assertEquals('v1.1.2', App::getLatestVersion($client));
}
}

View file

@ -1,9 +1,12 @@
<?php <?php
namespace Tests\Feature;
use App\Models\Artist; use App\Models\Artist;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\BrowserKitTestCase;
class ArtistTest extends TestCase class ArtistTest extends BrowserKitTestCase
{ {
use DatabaseTransactions; use DatabaseTransactions;
@ -30,7 +33,7 @@ class ArtistTest extends TestCase
public function testUtf16Names() public function testUtf16Names()
{ {
$name = file_get_contents(__DIR__.'/blobs/utf16'); $name = file_get_contents(__DIR__.'../../blobs/utf16');
$artist = Artist::get($name); $artist = Artist::get($name);
$artist = Artist::get($name); // to make sure there's no constraint exception $artist = Artist::get($name); // to make sure there's no constraint exception

View file

@ -1,13 +1,17 @@
<?php <?php
namespace Tests\Feature;
use App\Models\Album; use App\Models\Album;
use App\Models\Artist; use App\Models\Artist;
use App\Models\Playlist; use App\Models\Playlist;
use App\Models\Song; use App\Models\Song;
use App\Models\User; use App\Models\User;
use Download;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\BrowserKitTestCase;
class DownloadTest extends TestCase class DownloadTest extends BrowserKitTestCase
{ {
use DatabaseTransactions; use DatabaseTransactions;

View file

@ -1,12 +1,15 @@
<?php <?php
namespace Tests\Feature;
use App\Events\SongLikeToggled; use App\Events\SongLikeToggled;
use App\Models\Song; use App\Models\Song;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\BrowserKitTestCase;
class InteractionTest extends TestCase class InteractionTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;
@ -22,8 +25,7 @@ class InteractionTest extends TestCase
$user = factory(User::class)->create(); $user = factory(User::class)->create();
$song = Song::orderBy('id')->first(); $song = Song::orderBy('id')->first();
$this->actingAs($user) $this->postAsUser('api/interaction/play', ['song' => $song->id], $user);
->post('api/interaction/play', ['song' => $song->id]);
$this->seeInDatabase('interactions', [ $this->seeInDatabase('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -32,8 +34,7 @@ class InteractionTest extends TestCase
]); ]);
// Try again // Try again
$this->actingAs($user) $this->postAsUser('api/interaction/play', ['song' => $song->id], $user);
->post('api/interaction/play', ['song' => $song->id]);
$this->seeInDatabase('interactions', [ $this->seeInDatabase('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -49,8 +50,7 @@ class InteractionTest extends TestCase
$user = factory(User::class)->create(); $user = factory(User::class)->create();
$song = Song::orderBy('id')->first(); $song = Song::orderBy('id')->first();
$this->actingAs($user) $this->postAsUser('api/interaction/like', ['song' => $song->id], $user);
->post('api/interaction/like', ['song' => $song->id]);
$this->seeInDatabase('interactions', [ $this->seeInDatabase('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -59,8 +59,7 @@ class InteractionTest extends TestCase
]); ]);
// Try again // Try again
$this->actingAs($user) $this->postAsUser('api/interaction/like', ['song' => $song->id], $user);
->post('api/interaction/like', ['song' => $song->id]);
$this->seeInDatabase('interactions', [ $this->seeInDatabase('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -78,8 +77,7 @@ class InteractionTest extends TestCase
$songs = Song::orderBy('id')->take(2)->get(); $songs = Song::orderBy('id')->take(2)->get();
$songIds = array_pluck($songs->toArray(), 'id'); $songIds = array_pluck($songs->toArray(), 'id');
$this->actingAs($user) $this->postAsUser('api/interaction/batch/like', ['songs' => $songIds], $user);
->post('api/interaction/batch/like', ['songs' => $songIds]);
foreach ($songs as $song) { foreach ($songs as $song) {
$this->seeInDatabase('interactions', [ $this->seeInDatabase('interactions', [
@ -89,8 +87,7 @@ class InteractionTest extends TestCase
]); ]);
} }
$this->actingAs($user) $this->postAsUser('api/interaction/batch/unlike', ['songs' => $songIds], $user);
->post('api/interaction/batch/unlike', ['songs' => $songIds]);
foreach ($songs as $song) { foreach ($songs as $song) {
$this->seeInDatabase('interactions', [ $this->seeInDatabase('interactions', [

View file

@ -1,5 +1,7 @@
<?php <?php
namespace Tests\Feature;
use App\Events\SongLikeToggled; use App\Events\SongLikeToggled;
use App\Events\SongStartedPlaying; use App\Events\SongStartedPlaying;
use App\Http\Controllers\API\LastfmController; use App\Http\Controllers\API\LastfmController;
@ -17,16 +19,17 @@ use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Redirector; use Illuminate\Routing\Redirector;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
use Tymon\JWTAuth\JWTAuth; use Tymon\JWTAuth\JWTAuth;
class LastfmTest extends TestCase class LastfmTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;
public function testGetArtistInfo() public function testGetArtistInfo()
{ {
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(200, [], file_get_contents(__DIR__.'/blobs/lastfm/artist.xml')), 'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/lastfm/artist.xml')),
]); ]);
$api = new Lastfm(null, null, $client); $api = new Lastfm(null, null, $client);
@ -47,7 +50,7 @@ class LastfmTest extends TestCase
public function testGetArtistInfoFailed() public function testGetArtistInfoFailed()
{ {
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(400, [], file_get_contents(__DIR__.'/blobs/lastfm/artist-notfound.xml')), 'get' => new Response(400, [], file_get_contents(__DIR__.'../../blobs/lastfm/artist-notfound.xml')),
]); ]);
$api = new Lastfm(null, null, $client); $api = new Lastfm(null, null, $client);
@ -58,7 +61,7 @@ class LastfmTest extends TestCase
public function testGetAlbumInfo() public function testGetAlbumInfo()
{ {
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(200, [], file_get_contents(__DIR__.'/blobs/lastfm/album.xml')), 'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/lastfm/album.xml')),
]); ]);
$api = new Lastfm(null, null, $client); $api = new Lastfm(null, null, $client);
@ -91,7 +94,7 @@ class LastfmTest extends TestCase
public function testGetAlbumInfoFailed() public function testGetAlbumInfoFailed()
{ {
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(400, [], file_get_contents(__DIR__.'/blobs/lastfm/album-notfound.xml')), 'get' => new Response(400, [], file_get_contents(__DIR__.'../../blobs/lastfm/album-notfound.xml')),
]); ]);
$api = new Lastfm(null, null, $client); $api = new Lastfm(null, null, $client);
@ -121,7 +124,7 @@ class LastfmTest extends TestCase
public function testGetSessionKey() public function testGetSessionKey()
{ {
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(200, [], file_get_contents(__DIR__.'/blobs/lastfm/session-key.xml')), 'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/lastfm/session-key.xml')),
]); ]);
$api = new Lastfm(null, null, $client); $api = new Lastfm(null, null, $client);
@ -132,7 +135,8 @@ class LastfmTest extends TestCase
public function testSetSessionKey() public function testSetSessionKey()
{ {
$user = factory(User::class)->create(); $user = factory(User::class)->create();
$this->actingAs($user)->post('api/lastfm/session-key', ['key' => 'foo']); $this->postAsUser('api/lastfm/session-key', ['key' => 'foo'], $user);
$user = User::find($user->id);
$this->assertEquals('foo', $user->lastfm_session_key); $this->assertEquals('foo', $user->lastfm_session_key);
} }
@ -166,7 +170,8 @@ class LastfmTest extends TestCase
public function testControllerDisconnect() public function testControllerDisconnect()
{ {
$user = factory(User::class)->create(['preferences' => ['lastfm_session_key' => 'bar']]); $user = factory(User::class)->create(['preferences' => ['lastfm_session_key' => 'bar']]);
$this->actingAs($user)->delete('api/lastfm/disconnect'); $this->deleteAsUser('api/lastfm/disconnect', [], $user);
$user = User::find($user->id);
$this->assertNull($user->lastfm_session_key); $this->assertNull($user->lastfm_session_key);
} }

View file

@ -1,5 +1,7 @@
<?php <?php
namespace Tests\Feature;
use App\Events\LibraryChanged; use App\Events\LibraryChanged;
use App\Libraries\WatchRecord\InotifyWatchRecord; use App\Libraries\WatchRecord\InotifyWatchRecord;
use App\Models\Album; use App\Models\Album;
@ -10,8 +12,9 @@ use App\Services\Media;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
class MediaTest extends TestCase class MediaTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;

View file

@ -1,13 +1,22 @@
<?php <?php
namespace Tests\Feature\ObjectStorage;
use App\Events\LibraryChanged; use App\Events\LibraryChanged;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\BrowserKitTestCase;
class ObjectStorage_S3Test extends TestCase class S3Test extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;
public function setUp()
{
parent::setUp();
$this->withoutMiddleware();
}
public function testPut() public function testPut()
{ {
$this->post('api/os/s3/song', [ $this->post('api/os/s3/song', [
@ -27,7 +36,6 @@ class ObjectStorage_S3Test extends TestCase
public function testRemove() public function testRemove()
{ {
$this->expectsEvents(LibraryChanged::class); $this->expectsEvents(LibraryChanged::class);
$this->post('api/os/s3/song', [ $this->post('api/os/s3/song', [
'bucket' => 'koel', 'bucket' => 'koel',
'key' => 'sample.mp3', 'key' => 'sample.mp3',

View file

@ -1,11 +1,14 @@
<?php <?php
namespace Tests\Feature;
use App\Models\Playlist; use App\Models\Playlist;
use App\Models\Song; use App\Models\Song;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\BrowserKitTestCase;
class PlaylistTest extends TestCase class PlaylistTest extends BrowserKitTestCase
{ {
use DatabaseTransactions; use DatabaseTransactions;

View file

@ -1,17 +1,20 @@
<?php <?php
namespace Tests\Feature;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\BrowserKitTestCase;
class ProfileTest extends TestCase class ProfileTest extends BrowserKitTestCase
{ {
use WithoutMiddleware, DatabaseTransactions; use WithoutMiddleware, DatabaseTransactions;
public function testUpdate() public function testUpdate()
{ {
$this->actingAs(factory(User::class)->create()) $user = factory(User::class)->create();
->put('api/me', ['name' => 'Foo', 'email' => 'bar@baz.com']); $this->putAsUser('api/me', ['name' => 'Foo', 'email' => 'bar@baz.com'], $user);
$this->seeInDatabase('users', ['name' => 'Foo', 'email' => 'bar@baz.com']); $this->seeInDatabase('users', ['name' => 'Foo', 'email' => 'bar@baz.com']);
} }

View file

@ -1,13 +1,16 @@
<?php <?php
namespace Tests\Feature;
use App\Services\RESTfulService; use App\Services\RESTfulService;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Response;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
class RESTfulAPIServiceTest extends TestCase class RESTfulAPIServiceTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;

View file

@ -1,12 +1,15 @@
<?php <?php
namespace Tests\Feature;
use App\Models\Song; use App\Models\Song;
use App\Services\Lastfm; use App\Services\Lastfm;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
class ScrobbleTest extends TestCase class ScrobbleTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;

View file

@ -1,11 +1,15 @@
<?php <?php
namespace Tests\Feature;
use App\Models\Setting; use App\Models\Setting;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Media;
use Tests\BrowserKitTestCase;
class SettingTest extends TestCase class SettingTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;
@ -48,8 +52,8 @@ class SettingTest extends TestCase
{ {
Media::shouldReceive('sync')->once(); Media::shouldReceive('sync')->once();
$this->actingAs(factory(User::class, 'admin')->create()) $user = factory(User::class, 'admin')->create();
->post('/api/settings', ['media_path' => __DIR__]) $this->postAsUser('/api/settings', ['media_path' => __DIR__], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$this->assertEquals(__DIR__, Setting::get('media_path')); $this->assertEquals(__DIR__, Setting::get('media_path'));

View file

@ -1,17 +1,21 @@
<?php <?php
namespace Tests\Feature;
use App\Events\LibraryChanged; use App\Events\LibraryChanged;
use App\Models\Album; use App\Models\Album;
use App\Models\Artist; use App\Models\Artist;
use App\Models\Song; use App\Models\Song;
use App\Models\User; use App\Models\User;
use Aws\AwsClient; use Aws\AwsClient;
use Cache;
use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Request;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
class SongTest extends TestCase class SongTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;
@ -26,8 +30,8 @@ class SongTest extends TestCase
$this->expectsEvents(LibraryChanged::class); $this->expectsEvents(LibraryChanged::class);
$song = Song::orderBy('id', 'desc')->first(); $song = Song::orderBy('id', 'desc')->first();
$this->actingAs(factory(User::class, 'admin')->create()) $user = factory(User::class, 'admin')->create();
->put('/api/songs', [ $this->putAsUser('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Foo Bar', 'title' => 'Foo Bar',
@ -37,7 +41,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 0, 'compilationState' => 0,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$artist = Artist::whereName('John Cena')->first(); $artist = Artist::whereName('John Cena')->first();
@ -59,8 +63,8 @@ class SongTest extends TestCase
$song = Song::orderBy('id', 'desc')->first(); $song = Song::orderBy('id', 'desc')->first();
$originalArtistId = $song->album->artist->id; $originalArtistId = $song->album->artist->id;
$this->actingAs(factory(User::class, 'admin')->create()) $user = factory(User::class, 'admin')->create();
->put('/api/songs', [ $this->putAsUser('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => '', 'title' => '',
@ -70,7 +74,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 0, 'compilationState' => 0,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
// We don't expect the song's artist to change // We don't expect the song's artist to change
@ -84,8 +88,8 @@ class SongTest extends TestCase
{ {
$songIds = Song::orderBy('id', 'desc')->take(3)->pluck('id')->toArray(); $songIds = Song::orderBy('id', 'desc')->take(3)->pluck('id')->toArray();
$this->actingAs(factory(User::class, 'admin')->create()) $user = factory(User::class, 'admin')->create();
->put('/api/songs', [ $this->putAsUser('/api/songs', [
'songs' => $songIds, 'songs' => $songIds,
'data' => [ 'data' => [
'title' => 'foo', 'title' => 'foo',
@ -95,7 +99,7 @@ class SongTest extends TestCase
'track' => 9999, 'track' => 9999,
'compilationState' => 0, 'compilationState' => 0,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$songs = Song::orderBy('id', 'desc')->take(3)->get(); $songs = Song::orderBy('id', 'desc')->take(3)->get();
@ -121,8 +125,8 @@ class SongTest extends TestCase
$originalSongs = Song::orderBy('id', 'desc')->take(3)->get(); $originalSongs = Song::orderBy('id', 'desc')->take(3)->get();
$songIds = $originalSongs->pluck('id')->toArray(); $songIds = $originalSongs->pluck('id')->toArray();
$this->actingAs(factory(User::class, 'admin')->create()) $user = factory(User::class, 'admin')->create();
->put('/api/songs', [ $this->putAsUser('/api/songs', [
'songs' => $songIds, 'songs' => $songIds,
'data' => [ 'data' => [
'title' => 'Foo Bar', 'title' => 'Foo Bar',
@ -132,7 +136,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 0, 'compilationState' => 0,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$songs = Song::orderBy('id', 'desc')->take(3)->get(); $songs = Song::orderBy('id', 'desc')->take(3)->get();
@ -154,11 +158,10 @@ class SongTest extends TestCase
public function testSingleUpdateAllInfoYesCompilation() public function testSingleUpdateAllInfoYesCompilation()
{ {
$admin = factory(User::class, 'admin')->create();
$song = Song::orderBy('id', 'desc')->first(); $song = Song::orderBy('id', 'desc')->first();
$this->actingAs($admin) $user = factory(User::class, 'admin')->create();
->put('/api/songs', [ $this->putAsUser('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Foo Bar', 'title' => 'Foo Bar',
@ -168,7 +171,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 1, 'compilationState' => 1,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$compilationAlbum = Album::whereArtistIdAndName(Artist::VARIOUS_ID, 'One by One')->first(); $compilationAlbum = Album::whereArtistIdAndName(Artist::VARIOUS_ID, 'One by One')->first();
@ -187,8 +190,7 @@ class SongTest extends TestCase
// Now try changing stuff and make sure things work. // Now try changing stuff and make sure things work.
// Case 1: Keep compilation state and artist the same // Case 1: Keep compilation state and artist the same
$this->actingAs($admin) $this->putAsUser('/api/songs', [
->put('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Barz Qux', 'title' => 'Barz Qux',
@ -198,7 +200,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 2, 'compilationState' => 2,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$compilationAlbum = Album::whereArtistIdAndName(Artist::VARIOUS_ID, 'Two by Two')->first(); $compilationAlbum = Album::whereArtistIdAndName(Artist::VARIOUS_ID, 'Two by Two')->first();
@ -214,8 +216,7 @@ class SongTest extends TestCase
]); ]);
// Case 2: Keep compilation state, but change the artist. // Case 2: Keep compilation state, but change the artist.
$this->actingAs($admin) $this->putAsUser('/api/songs', [
->put('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Barz Qux', 'title' => 'Barz Qux',
@ -225,7 +226,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 2, 'compilationState' => 2,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$compilationAlbum = Album::whereArtistIdAndName(Artist::VARIOUS_ID, 'One by One')->first(); $compilationAlbum = Album::whereArtistIdAndName(Artist::VARIOUS_ID, 'One by One')->first();
@ -241,8 +242,7 @@ class SongTest extends TestCase
]); ]);
// Case 3: Change compilation state only // Case 3: Change compilation state only
$this->actingAs($admin) $this->putAsUser('/api/songs', [
->put('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Barz Qux', 'title' => 'Barz Qux',
@ -252,7 +252,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 0, 'compilationState' => 0,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$artist = Artist::whereName('Foo Fighters')->first(); $artist = Artist::whereName('Foo Fighters')->first();
@ -267,8 +267,7 @@ class SongTest extends TestCase
// Case 3: Change compilation state and artist // Case 3: Change compilation state and artist
// Remember to set the compliation state back to 1 // Remember to set the compliation state back to 1
$this->actingAs($admin) $this->putAsUser('/api/songs', [
->put('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Barz Qux', 'title' => 'Barz Qux',
@ -278,9 +277,8 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 1, 'compilationState' => 1,
], ],
]) ], $user)
->putAsUser('/api/songs', [
->put('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Twilight of the Thunder God', 'title' => 'Twilight of the Thunder God',
@ -290,7 +288,7 @@ class SongTest extends TestCase
'track' => 1, 'track' => 1,
'compilationState' => 0, 'compilationState' => 0,
], ],
]) ], $user)
->seeStatusCode(200); ->seeStatusCode(200);
$artist = Artist::whereName('Amon Amarth')->first(); $artist = Artist::whereName('Amon Amarth')->first();

View file

@ -1,9 +1,12 @@
<?php <?php
namespace Tests\Feature;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\BrowserKitTestCase;
class UserTest extends TestCase class UserTest extends BrowserKitTestCase
{ {
use DatabaseTransactions; use DatabaseTransactions;

View file

@ -1,5 +1,7 @@
<?php <?php
namespace Tests\Feature;
use App\Models\Song; use App\Models\Song;
use App\Services\YouTube; use App\Services\YouTube;
use GuzzleHttp\Client; use GuzzleHttp\Client;
@ -7,9 +9,10 @@ use GuzzleHttp\Psr7\Response;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
use YouTube as YouTubeFacade; use YouTube as YouTubeFacade;
class YouTubeTest extends TestCase class YouTubeTest extends BrowserKitTestCase
{ {
use DatabaseTransactions, WithoutMiddleware; use DatabaseTransactions, WithoutMiddleware;
@ -18,7 +21,7 @@ class YouTubeTest extends TestCase
$this->withoutEvents(); $this->withoutEvents();
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(200, [], file_get_contents(__DIR__.'/blobs/youtube/search.json')), 'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/youtube/search.json')),
]); ]);
$api = new YouTube(null, $client); $api = new YouTube(null, $client);
@ -38,6 +41,6 @@ class YouTubeTest extends TestCase
// We test on the facade here // We test on the facade here
YouTubeFacade::shouldReceive('searchVideosRelatedToSong')->once(); YouTubeFacade::shouldReceive('searchVideosRelatedToSong')->once();
$this->visit("/api/youtube/search/song/{$song->id}"); $this->getAsUser("/api/youtube/search/song/{$song->id}");
} }
} }

View file

@ -1,19 +1,22 @@
<?php <?php
namespace Tests\Feature;
use App\Services\iTunes; use App\Services\iTunes;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Response;
use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\WithoutMiddleware;
use Mockery as m; use Mockery as m;
use Tests\BrowserKitTestCase;
class iTunesTest extends TestCase class iTunesTest extends BrowserKitTestCase
{ {
use WithoutMiddleware; use WithoutMiddleware;
public function testGetTrackUrl() public function testGetTrackUrl()
{ {
$client = m::mock(Client::class, [ $client = m::mock(Client::class, [
'get' => new Response(200, [], file_get_contents(__DIR__.'/blobs/itunes/track.json')), 'get' => new Response(200, [], file_get_contents(__DIR__.'../../blobs/itunes/track.json')),
]); ]);
$api = new iTunes($client); $api = new iTunes($client);

View file

@ -1,127 +1,10 @@
<?php <?php
use App\Models\Album; namespace Tests;
use App\Models\Artist;
use App\Models\Song;
use App\Models\User;
use Illuminate\Foundation\Testing\TestCase as IlluminateTestCase;
use Illuminate\Support\Facades\Artisan;
abstract class TestCase extends IlluminateTestCase use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{ {
protected $mediaPath; use CreatesApplication;
protected $coverPath;
public function __construct()
{
parent::__construct();
$this->mediaPath = __DIR__.'/songs';
}
public function setUp()
{
parent::setUp();
$this->prepareForTests();
}
/**
* The base URL to use while testing the application.
*
* @var string
*/
protected $baseUrl = 'http://localhost';
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$this->coverPath = $app->basePath().'/public/img/covers';
return $app;
}
private function prepareForTests()
{
Artisan::call('migrate');
if (!User::all()->count()) {
Artisan::call('db:seed');
}
if (!file_exists($this->coverPath)) {
mkdir($this->coverPath, 0777, true);
}
}
/**
* Create a sample media set, with a complete artist+album+song trio.
*/
protected function createSampleMediaSet()
{
$artist = factory(Artist::class)->create();
// Sample 3 albums
$albums = factory(Album::class, 3)->create([
'artist_id' => $artist->id,
]);
// 7-15 songs per albums
foreach ($albums as $album) {
factory(Song::class, random_int(7, 15))->create([
'album_id' => $album->id,
]);
}
}
protected function getAsUser($url, $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->get($url, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
protected function deleteAsUser($url, $data = [], $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->delete($url, $data, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
protected function postAsUser($url, $data, $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->post($url, $data, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
protected function putAsUser($url, $data, $user = null)
{
if (!$user) {
$user = factory(User::class)->create();
}
return $this->put($url, $data, [
'Authorization' => 'Bearer '.JWTAuth::fromUser($user),
]);
}
} }

View file

@ -0,0 +1,20 @@
<?php
namespace Tests\Unit;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$this->assertTrue(true);
}
}

View file

@ -1,4 +1,4 @@
{ {
"foo.css": "foo00.css", "/foo.css": "/foo00.css",
"bar.js": "bar00.js" "/bar.js": "/bar00.js"
} }

393
webpack.config.js Normal file
View file

@ -0,0 +1,393 @@
let path = require('path');
let webpack = require('webpack');
let Mix = require('laravel-mix').config;
let plugins = require('laravel-mix').plugins;
/*
|--------------------------------------------------------------------------
| Mix Initialization
|--------------------------------------------------------------------------
|
| As our first step, we'll require the project's Laravel Mix file
| and record the user's requested compilation and build steps.
| Once those steps have been recorded, we may get to work.
|
*/
Mix.initialize();
/*
|--------------------------------------------------------------------------
| Webpack Context
|--------------------------------------------------------------------------
|
| This prop will determine the appropriate context, when running Webpack.
| Since you have the option of publishing this webpack.config.js file
| to your project root, we will dynamically set the path for you.
|
*/
module.exports.context = Mix.Paths.root();
/*
|--------------------------------------------------------------------------
| Webpack Entry
|--------------------------------------------------------------------------
|
| We'll first specify the entry point for Webpack. By default, we'll
| assume a single bundled file, but you may call Mix.extract()
| to make a separate bundle specifically for vendor libraries.
|
*/
module.exports.entry = Mix.entry();
/*
|--------------------------------------------------------------------------
| Webpack Output
|--------------------------------------------------------------------------
|
| Webpack naturally requires us to specify our desired output path and
| file name. We'll simply echo what you passed to with Mix.js().
| Note that, for Mix.version(), we'll properly hash the file.
|
*/
module.exports.output = Mix.output();
/*
|--------------------------------------------------------------------------
| Rules
|--------------------------------------------------------------------------
|
| Webpack rules allow us to register any number of loaders and options.
| Out of the box, we'll provide a handful to get you up and running
| as quickly as possible, though feel free to add to this list.
|
*/
module.exports.module = {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: Mix.options.extractVueStyles ? {
js: 'babel-loader' + Mix.babelConfig(),
scss: plugins.ExtractTextPlugin.extract({
use: 'css-loader!sass-loader',
fallback: 'vue-style-loader'
}),
sass: plugins.ExtractTextPlugin.extract({
use: 'css-loader!sass-loader?indentedSyntax',
fallback: 'vue-style-loader'
}),
css: plugins.ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
})
}: {
js: 'babel-loader' + Mix.babelConfig(),
scss: 'vue-style-loader!css-loader!sass-loader',
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
},
postcss: [
require('autoprefixer')
]
}
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader' + Mix.babelConfig()
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
},
{
test: /\.html$/,
loaders: ['html-loader']
},
{
test: /\.(png|jpg|gif)$/,
loader: 'file-loader',
options: {
name: 'images/[name].[ext]?[hash]',
publicPath: '/public/'
}
},
{
test: /\.(woff2?|ttf|eot|svg|otf)$/,
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]?[hash]',
publicPath: '/public/'
}
}
]
};
if (Mix.preprocessors) {
Mix.preprocessors.forEach(toCompile => {
let extractPlugin = new plugins.ExtractTextPlugin(
Mix.cssOutput(toCompile)
);
let sourceMap = Mix.sourcemaps ? '?sourceMap' : '';
module.exports.module.rules.push({
test: new RegExp(toCompile.src.path.replace(/\\/g, '\\\\') + '$'),
use: extractPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader' + sourceMap },
{ loader: 'postcss-loader' + sourceMap }
].concat(
toCompile.type == 'sass' ? [
{ loader: 'resolve-url-loader' + sourceMap },
{
loader: 'sass-loader',
options: Object.assign({
precision: 8,
outputStyle: 'expanded'
}, toCompile.pluginOptions, { sourceMap: true })
}
] : [
{
loader: 'less-loader' + sourceMap,
options: toCompile.pluginOptions
}
]
)
})
});
module.exports.plugins = (module.exports.plugins || []).concat(extractPlugin);
});
} else if (Mix.options.extractVueStyles) {
module.exports.plugins = (module.exports.plugins || []).concat(
new plugins.ExtractTextPlugin(path.join(Mix.js.base, 'vue-styles.css'))
);
}
/*
|--------------------------------------------------------------------------
| Resolve
|--------------------------------------------------------------------------
|
| Here, we may set any options/aliases that affect Webpack's resolving
| of modules. To begin, we will provide the necessary Vue alias to
| load the Vue common library. You may delete this, if needed.
|
*/
module.exports.resolve = {
extensions: ['*', '.js', '.jsx', '.vue'],
alias: {
'vue$': 'vue/dist/vue.common.js'
}
};
/*
|--------------------------------------------------------------------------
| Stats
|--------------------------------------------------------------------------
|
| By default, Webpack spits a lot of information out to the terminal,
| each you time you compile. Let's keep things a bit more minimal
| and hide a few of those bits and pieces. Adjust as you wish.
|
*/
module.exports.stats = {
hash: false,
version: false,
timings: false,
children: false,
errors: false
};
module.exports.performance = { hints: false };
/*
|--------------------------------------------------------------------------
| Devtool
|--------------------------------------------------------------------------
|
| Sourcemaps allow us to access our original source code within the
| browser, even if we're serving a bundled script or stylesheet.
| You may activate sourcemaps, by adding Mix.sourceMaps().
|
*/
module.exports.devtool = Mix.sourcemaps;
/*
|--------------------------------------------------------------------------
| Webpack Dev Server Configuration
|--------------------------------------------------------------------------
|
| If you want to use that flashy hot module replacement feature, then
| we've got you covered. Here, we'll set some basic initial config
| for the Node server. You very likely won't want to edit this.
|
*/
module.exports.devServer = {
historyApiFallback: true,
noInfo: true,
compress: true,
quiet: true
};
/*
|--------------------------------------------------------------------------
| Plugins
|--------------------------------------------------------------------------
|
| Lastly, we'll register a number of plugins to extend and configure
| Webpack. To get you started, we've included a handful of useful
| extensions, for versioning, OS notifications, and much more.
|
*/
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.ProvidePlugin(Mix.autoload || {
jQuery: 'jquery',
$: 'jquery',
jquery: 'jquery',
'window.jQuery': 'jquery'
}),
new plugins.FriendlyErrorsWebpackPlugin(),
new plugins.StatsWriterPlugin({
filename: 'mix-manifest.json',
transform: Mix.manifest.transform.bind(Mix.manifest),
}),
new plugins.WebpackMd5HashPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: Mix.inProduction,
options: {
postcss: [
require('autoprefixer')
],
context: __dirname,
output: { path: './' }
}
})
]);
if (Mix.browserSync) {
module.exports.plugins.push(
new plugins.BrowserSyncPlugin(Object.assign({
host: 'localhost',
port: 3000,
proxy: 'app.dev',
files: [
'app/**/*.php',
'resources/views/**/*.php',
'public/mix-manifest.json',
'public/css/**/*.css',
'public/js/**/*.js'
]
}, Mix.browserSync))
);
}
module.exports.plugins.push(
new plugins.WebpackOnBuildPlugin(
stats => Mix.events.fire('build', stats)
)
);
if (Mix.notifications) {
module.exports.plugins.push(
new plugins.WebpackNotifierPlugin({
title: 'Laravel Mix',
alwaysNotify: true,
contentImage: Mix.Paths.root('node_modules/laravel-mix/icons/laravel.png')
})
);
}
if (Mix.copy) {
Mix.copy.forEach(copy => {
module.exports.plugins.push(
new plugins.CopyWebpackPlugin([copy])
);
});
}
if (Mix.extract) {
module.exports.plugins.push(
new webpack.optimize.CommonsChunkPlugin({
names: Mix.entryBuilder.extractions.concat([
path.join(Mix.js.base, 'manifest').replace(/\\/g, '/')
]),
minChunks: Infinity
})
);
}
if (Mix.inProduction) {
module.exports.plugins = module.exports.plugins.concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false,
drop_console: true
}
})
]);
}
/*
|--------------------------------------------------------------------------
| Mix Finalizing
|--------------------------------------------------------------------------
|
| Now that we've declared the entirety of our Webpack configuration, the
| final step is to scan for any custom configuration in the Mix file.
| If mix.webpackConfig() is called, we'll merge it in, and build!
|
*/
Mix.finalize(module.exports);

28
webpack.mix.js Normal file
View file

@ -0,0 +1,28 @@
const mix = require('laravel-mix');
const fs = require('fs');
mix.config.detectHotReloading()
if (mix.config.hmr) {
// There's a bug with Mix/copy plugin which prevents HMR from working:
// https://github.com/JeffreyWay/laravel-mix/issues/150
console.log('In HMR mode. If assets are missing, Ctr+C and run `yarn dev` first.');
// Somehow public/hot isn't being removed by Mix. We'll handle it ourselves.
process.on('SIGINT', () => {
try {
fs.unlinkSync(mix.config.publicPath + '/hot');
} catch (e) {}
process.exit();
});
} else {
mix.copy('resources/assets/img', 'public/img')
.copy('node_modules/font-awesome/fonts', 'public/fonts');
}
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');
if (mix.config.inProduction) {
mix.version();
mix.disableNotifications();
}

4363
yarn.lock

File diff suppressed because it is too large Load diff