diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile index 71e8f507..fba144cd 100644 --- a/.gitpod.dockerfile +++ b/.gitpod.dockerfile @@ -1,3 +1,3 @@ FROM gitpod/workspace-mysql:latest -ENV APACHE_DOCROOT_IN_REPO="" +ENV APACHE_DOCROOT_IN_REPO="public" diff --git a/api-docs/index.html b/api-docs/index.html index e6852f32..ce97c8b7 100644 --- a/api-docs/index.html +++ b/api-docs/index.html @@ -2163,7 +2163,7 @@ fetch(url, {

Example response (200):

{
-    "artistUrl": "https:\/\/koel.host\/images\/artists\/new-cover.jpg"
+    "artistUrl": "https:\/\/koel.host\/img\/artists\/new-cover.jpg"
 }

HTTP Request

PUT api/artist/{artist}/image

@@ -3855,4 +3855,4 @@ fetch(url, { - \ No newline at end of file + diff --git a/api-docs/source/index.md b/api-docs/source/index.md index 891a3d66..58195e29 100644 --- a/api-docs/source/index.md +++ b/api-docs/source/index.md @@ -2236,7 +2236,7 @@ fetch(url, { ```json { - "artistUrl": "https:\/\/koel.host\/images\/artists\/new-cover.jpg" + "artistUrl": "https:\/\/koel.host\/img\/artists\/new-cover.jpg" } ``` diff --git a/app/Application.php b/app/Application.php index 1bd4fad2..d6d8d290 100644 --- a/app/Application.php +++ b/app/Application.php @@ -17,16 +17,6 @@ class Application extends IlluminateApplication */ public const KOEL_VERSION = 'v4.4.0'; - /** - * We have merged public path and base path. - * - * @return string - */ - public function publicPath() - { - return $this->basePath; - } - /** * Loads a revision'ed asset file, making use of gulp-rev * This is a copycat of L5's Elixir, but catered to our directory structure. @@ -37,16 +27,16 @@ class Application extends IlluminateApplication { static $manifest = null; - $manifestFile = $manifestFile ?: public_path('public/mix-manifest.json'); + $manifestFile = $manifestFile ?: public_path('mix-manifest.json'); if ($manifest === null) { $manifest = json_decode(file_get_contents($manifestFile), true); } if (isset($manifest[$file])) { - return file_exists(public_path('public/hot')) - ? "http://localhost:8080/public{$manifest[$file]}" - : $this->staticUrl("public{$manifest[$file]}"); + return file_exists(public_path('hot')) + ? "http://localhost:8080{$manifest[$file]}" + : $this->staticUrl("{$manifest[$file]}"); } throw new InvalidArgumentException("File {$file} not defined in asset manifest."); diff --git a/app/Http/Controllers/API/AlbumThumbnailController.php b/app/Http/Controllers/API/AlbumThumbnailController.php index 577199cc..6c156740 100644 --- a/app/Http/Controllers/API/AlbumThumbnailController.php +++ b/app/Http/Controllers/API/AlbumThumbnailController.php @@ -24,7 +24,7 @@ class AlbumThumbnailController extends Controller * Get an album's thumbnail (a 48px-wide blurry version of the album's cover). * Returns the full URL to the thumbnail or NULL if the album has no cover. * - * @response ["thumbnailUrl", "https://localhost/public/img/covers/a146d01afb742b01f28ab8b556f9a75d_thumbnail.jpg"] + * @response ["thumbnailUrl", "https://localhost/img/covers/a146d01afb742b01f28ab8b556f9a75d_thumbnail.jpg"] */ public function get(Album $album): JsonResponse { diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 98dadc16..b061c682 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -21,7 +21,7 @@ class RedirectIfAuthenticated public function handle(Request $request, Closure $next) { if ($this->auth->check()) { - return redirect('/♫'); + return redirect('/'); } return $next($request); diff --git a/app/Http/Middleware/UseDifferentConfigIfE2E.php b/app/Http/Middleware/UseDifferentConfigIfE2E.php deleted file mode 100644 index 79d1dc47..00000000 --- a/app/Http/Middleware/UseDifferentConfigIfE2E.php +++ /dev/null @@ -1,25 +0,0 @@ - 'sqlite-e2e']); - } - - return $next($request); - } -} diff --git a/bootstrap/app.php b/bootstrap/app.php index 485761ec..873df5d9 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -11,7 +11,7 @@ | */ -$app = new App\Application(__DIR__.'/../'); +$app = new App\Application(dirname(__DIR__)); /* |-------------------------------------------------------------------------- diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php index 94adc997..a3f411df 100644 --- a/bootstrap/autoload.php +++ b/bootstrap/autoload.php @@ -1,7 +1,5 @@ env('MEDIA_PATH'), // The *relative* path to the directory to store album covers and thumbnails, *with* a trailing slash. - 'album_cover_dir' => 'public/img/covers/', + 'album_cover_dir' => 'img/covers/', // The *relative* path to the directory to store artist images, *with* a trailing slash. - 'artist_image_dir' => 'public/img/artists/', + 'artist_image_dir' => 'img/artists/', /* |-------------------------------------------------------------------------- diff --git a/nginx.conf.example b/nginx.conf.example index 73865627..1213a9a7 100644 --- a/nginx.conf.example +++ b/nginx.conf.example @@ -1,18 +1,13 @@ server { listen *:80; server_name koel.dev; - root /var/www/koel; + root /var/www/koel/public; index index.php; gzip on; gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json; gzip_comp_level 9; - # Whitelist only index.php, robots.txt, and some special routes - if ($request_uri !~ ^/$|index\.php|robots\.txt|(public|api|web)/|remote|api-docs|sw\.js) { - return 404; - } - location /media/ { internal; diff --git a/public/.gitignore b/public/.gitignore index 41773c48..b7420814 100644 --- a/public/.gitignore +++ b/public/.gitignore @@ -1,5 +1,7 @@ -* -!.gitignore -!manifest.json.example -!manifest-remote.json.example -!browserconfig.xml +css +fonts +img +js +manifest.json +manifest-remote.json +hot diff --git a/.htaccess b/public/.htaccess similarity index 88% rename from .htaccess rename to public/.htaccess index a286c45b..675c8eda 100644 --- a/.htaccess +++ b/public/.htaccess @@ -6,26 +6,24 @@ - Options -MultiViews + Options -MultiViews -Indexes RewriteEngine On - RewriteBase / - # Redirect Trailing Slashes... - RewriteRule ^(.*)/$ /$1 [L,R=301] + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - # Whitelist only index.php, robots.txt, and some special routes - RewriteRule ^(?!($|index\.php|robots\.txt|(public|api|web)/|remote|api-docs|sw\.js)) - [R=404,L] + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule .* index.php [L] - - # https://github.com/tymondesigns/jwt-auth/wiki/Authentication - RewriteCond %{HTTP:Authorization} ^(.*) - RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] + RewriteRule ^ index.php [L] @@ -52,7 +50,7 @@ # Disable deflation for media files. - SetEnvIfNoCase Request_URI "^/api/play/" no-gzip dont-vary + SetEnvIfNoCase Request_URI "^/play/" no-gzip dont-vary # ---------------------------------------------------------------------- # Gzip compression. diff --git a/public/browserconfig.xml b/public/browserconfig.xml index 592aecd0..798bf151 100644 --- a/public/browserconfig.xml +++ b/public/browserconfig.xml @@ -3,10 +3,10 @@ - - - - + + + + diff --git a/index.php b/public/index.php similarity index 82% rename from index.php rename to public/index.php index 67464e51..fff8e99b 100644 --- a/index.php +++ b/public/index.php @@ -18,7 +18,12 @@ | */ -require __DIR__.'/bootstrap/autoload.php'; +use Illuminate\Contracts\Http\Kernel; +use Illuminate\Http\Request; + +define('LARAVEL_START', microtime(true)); + +require __DIR__.'/../bootstrap/autoload.php'; /* |-------------------------------------------------------------------------- @@ -32,7 +37,7 @@ require __DIR__.'/bootstrap/autoload.php'; | */ -$app = require_once __DIR__.'/bootstrap/app.php'; +$app = require_once __DIR__.'/../bootstrap/app.php'; /* |-------------------------------------------------------------------------- @@ -46,12 +51,10 @@ $app = require_once __DIR__.'/bootstrap/app.php'; | */ -$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); +$kernel = $app->make(Kernel::class); -$response = $kernel->handle( - $request = Illuminate\Http\Request::capture() -); - -$response->send(); +$response = tap($kernel->handle( + $request = Request::capture() +))->send(); $kernel->terminate($request, $response); diff --git a/public/manifest-remote.json.example b/public/manifest-remote.json.example index 863aa170..067f84f8 100644 --- a/public/manifest-remote.json.example +++ b/public/manifest-remote.json.example @@ -4,7 +4,7 @@ "display": "standalone", "orientation": "portrait", "icons": [{ - "src": "/public/img/icon.png", + "src": "/img/icon.png", "sizes": "192x192", "type": "image/png" }], diff --git a/public/manifest.json.example b/public/manifest.json.example index 18834f41..98cdaa1b 100644 --- a/public/manifest.json.example +++ b/public/manifest.json.example @@ -4,7 +4,7 @@ "display": "standalone", "orientation": "portrait", "icons": [{ - "src": "/public/img/icon.png", + "src": "/img/icon.png", "sizes": "192x192", "type": "image/png" }], diff --git a/public/mix-manifest.json b/public/mix-manifest.json new file mode 100644 index 00000000..327abe54 --- /dev/null +++ b/public/mix-manifest.json @@ -0,0 +1,6 @@ +{ + "/js/app.js": "/js/app.js", + "/css/app.css": "/css/app.css", + "/css/remote.css": "/css/remote.css", + "/js/remote/app.js": "/js/remote/app.js" +} diff --git a/sw.js b/public/sw.js similarity index 100% rename from sw.js rename to public/sw.js diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index 91489473..30d20ad2 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -12,11 +12,11 @@ - - - - - + + + + + diff --git a/resources/views/remote.blade.php b/resources/views/remote.blade.php index 2b601e84..56e15dcd 100644 --- a/resources/views/remote.blade.php +++ b/resources/views/remote.blade.php @@ -13,11 +13,11 @@ - - - - - + + + + + diff --git a/routes/web.php b/routes/web.php index d9558f56..4a0dd4f9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -11,8 +11,8 @@ Route::get('/remote', static function () { return view('remote'); }); -Route::group(['middleware' => 'auth', 'prefix' => 'web'], static function (): void { - Route::get('/{song}/play/{transcode?}/{bitrate?}', 'PlayController@show') +Route::group(['middleware' => 'auth'], static function (): void { + Route::get('play/{song}/{transcode?}/{bitrate?}', 'PlayController@show') ->name('song.play'); Route::group(['prefix' => 'lastfm'], static function (): void { diff --git a/server.php b/server.php index 7df54b96..1b4655ba 100644 --- a/server.php +++ b/server.php @@ -12,8 +12,8 @@ $uri = urldecode( // This file allows us to emulate Apache's "mod_rewrite" functionality from the // built-in PHP web server. This provides a convenient way to test a Laravel // application without having installed a "real" web server software here. -if ($uri !== '/' && file_exists(__DIR__.$uri)) { +if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { return false; } -require_once __DIR__.'/index.php'; +require_once __DIR__.'/public/index.php'; diff --git a/storage/responses/albumCover.update.json b/storage/responses/albumCover.update.json index 80f4cc1b..3549ab23 100644 --- a/storage/responses/albumCover.update.json +++ b/storage/responses/albumCover.update.json @@ -1,3 +1,3 @@ { - "coverUrl": "https://koel.host/images/albums/new-cover.jpg" + "coverUrl": "https://koel.host/img/albums/new-cover.jpg" } diff --git a/storage/responses/artistImage.update.json b/storage/responses/artistImage.update.json index 5dcdde43..e6ba2f78 100644 --- a/storage/responses/artistImage.update.json +++ b/storage/responses/artistImage.update.json @@ -1,3 +1,3 @@ { - "imageUrl": "https://koel.host/images/artists/new-cover.jpg" + "imageUrl": "https://koel.host/img/artists/new-cover.jpg" } diff --git a/tests/Feature/AlbumThumbnailTest.php b/tests/Feature/AlbumThumbnailTest.php index 3914ba60..65057563 100644 --- a/tests/Feature/AlbumThumbnailTest.php +++ b/tests/Feature/AlbumThumbnailTest.php @@ -18,7 +18,7 @@ class AlbumThumbnailTest extends TestCase public function provideAlbumThumbnailData(): array { - return [['http://localhost/public/img/covers/foo_thumbnail.jpg'], [null]]; + return [['http://localhost/img/covers/foo_thumbnail.jpg'], [null]]; } /** @dataProvider provideAlbumThumbnailData */ diff --git a/tests/Feature/DownloadTest.php b/tests/Feature/DownloadTest.php index 8ac295ce..97a91912 100644 --- a/tests/Feature/DownloadTest.php +++ b/tests/Feature/DownloadTest.php @@ -41,7 +41,7 @@ class DownloadTest extends TestCase ->shouldReceive('from') ->never(); - $this->get("web/download/songs?songs[]={$song->id}") + $this->get("download/songs?songs[]={$song->id}") ->assertRedirect('/'); } @@ -60,7 +60,7 @@ class DownloadTest extends TestCase })) ->andReturn($this->mediaPath.'/blank.mp3'); - $this->get("web/download/songs?songs[]={$song->id}&api_token=".$user->createToken('Koel')->plainTextToken) + $this->get("download/songs?songs[]={$song->id}&api_token=".$user->createToken('Koel')->plainTextToken) ->assertOk(); } @@ -83,7 +83,7 @@ class DownloadTest extends TestCase ->andReturn($this->mediaPath.'/blank.mp3'); // should be a zip file, but we're testing here… $this->get( - "web/download/songs?songs[]={$songs[0]->id}&songs[]={$songs[1]->id}&api_token=" + "download/songs?songs[]={$songs[0]->id}&songs[]={$songs[1]->id}&api_token=" .$user->createToken('Koel')->plainTextToken ) ->assertOk(); @@ -104,7 +104,7 @@ class DownloadTest extends TestCase })) ->andReturn($this->mediaPath.'/blank.mp3'); - $this->get("web/download/album/{$album->id}?api_token=".$user->createToken('Koel')->plainTextToken) + $this->get("download/album/{$album->id}?api_token=".$user->createToken('Koel')->plainTextToken) ->assertOk(); } @@ -123,7 +123,7 @@ class DownloadTest extends TestCase })) ->andReturn($this->mediaPath.'/blank.mp3'); - $this->get("web/download/artist/{$artist->id}?api_token=".$user->createToken('Koel')->plainTextToken) + $this->get("download/artist/{$artist->id}?api_token=".$user->createToken('Koel')->plainTextToken) ->assertOk(); } @@ -145,7 +145,7 @@ class DownloadTest extends TestCase ->once() ->andReturn($this->mediaPath.'/blank.mp3'); - $this->get("web/download/playlist/{$playlist->id}?api_token=".$user->createToken('Koel')->plainTextToken) + $this->get("download/playlist/{$playlist->id}?api_token=".$user->createToken('Koel')->plainTextToken) ->assertOk(); } @@ -157,7 +157,7 @@ class DownloadTest extends TestCase /** @var User $user */ $user = factory(User::class)->create(); - $this->get("web/download/playlist/{$playlist->id}?api_token=".$user->createToken('Koel')->plainTextToken) + $this->get("download/playlist/{$playlist->id}?api_token=".$user->createToken('Koel')->plainTextToken) ->assertStatus(Response::HTTP_FORBIDDEN); } @@ -181,7 +181,7 @@ class DownloadTest extends TestCase ->once() ->andReturn($this->mediaPath.'/blank.mp3'); - $this->get('web/download/favorites?api_token='.$user->createToken('Koel')->plainTextToken) + $this->get('download/favorites?api_token='.$user->createToken('Koel')->plainTextToken) ->assertOk(); } } diff --git a/tests/Feature/LastfmTest.php b/tests/Feature/LastfmTest.php index 303a4b32..8f813bd9 100644 --- a/tests/Feature/LastfmTest.php +++ b/tests/Feature/LastfmTest.php @@ -56,9 +56,9 @@ class LastfmTest extends TestCase ->with($user) ->andReturn($temporaryToken); - $this->get('web/lastfm/connect?api_token='.$token) + $this->get('lastfm/connect?api_token='.$token) ->assertRedirect( - 'https://www.last.fm/api/auth/?api_key=foo&cb=http%3A%2F%2Flocalhost%2Fweb%2Flastfm%2Fcallback%3Fapi_token%3Dtmp-token' + 'https://www.last.fm/api/auth/?api_key=foo&cb=http%3A%2F%2Flocalhost%2Flastfm%2Fcallback%3Fapi_token%3Dtmp-token' ); } @@ -77,7 +77,7 @@ class LastfmTest extends TestCase ->once() ->andReturn('my-session-key'); - $this->get('web/lastfm/callback?token=lastfm-token&api_token='.urlencode($token)) + $this->get('lastfm/callback?token=lastfm-token&api_token='.urlencode($token)) ->assertOk(); self::assertSame('my-session-key', $user->refresh()->lastfm_session_key); @@ -102,7 +102,7 @@ class LastfmTest extends TestCase ->with('my-token') ->andReturn($user); - $this->get('web/lastfm/callback?token=foo&api_token=my-token'); + $this->get('lastfm/callback?token=foo&api_token=my-token'); self::assertEquals('bar', $user->refresh()->lastfm_session_key); } diff --git a/tests/Traits/SandboxesTests.php b/tests/Traits/SandboxesTests.php index f677b6b6..8dd3897a 100644 --- a/tests/Traits/SandboxesTests.php +++ b/tests/Traits/SandboxesTests.php @@ -8,15 +8,15 @@ trait SandboxesTests { private static function createSandbox(): void { - config(['koel.album_cover_dir' => 'public/sandbox/img/covers/']); - config(['koel.artist_image_dir' => 'public/sandbox/img/artists/']); + config(['koel.album_cover_dir' => 'sandbox/img/covers/']); + config(['koel.artist_image_dir' => 'sandbox/img/artists/']); - @mkdir(base_path(config('koel.album_cover_dir')), 0755, true); - @mkdir(base_path(config('koel.artist_image_dir')), 0755, true); + @mkdir(public_path(config('koel.album_cover_dir')), 0755, true); + @mkdir(public_path(config('koel.artist_image_dir')), 0755, true); } private static function destroySandbox(): void { - File::deleteDirectory(base_path('public/sandbox')); + File::deleteDirectory(public_path('sandbox')); } } diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php index 911adcdd..b51df471 100644 --- a/tests/Unit/ApplicationTest.php +++ b/tests/Unit/ApplicationTest.php @@ -9,7 +9,8 @@ class ApplicationTest extends TestCase public function setUp(): void { parent::setUp(); - @unlink(app()->publicPath().'/public/hot'); + + @unlink(public_path('hot')); } /** @test */ @@ -55,7 +56,7 @@ class ApplicationTest extends TestCase $assetURL = app()->rev('/foo.css', $manifestFile); // Then I see they're constructed correctly - self::assertEquals('http://localhost/public/foo00.css', $assetURL); + self::assertEquals('http://localhost/foo00.css', $assetURL); } /** @test */ @@ -71,6 +72,6 @@ class ApplicationTest extends TestCase $assetURL = app()->rev('/foo.css', $manifestFile); // Then I see they're constructed correctly - self::assertEquals('http://cdn.tld/public/foo00.css', $assetURL); + self::assertEquals('http://cdn.tld/foo00.css', $assetURL); } } diff --git a/tests/Unit/Services/MediaMetadataServiceTest.php b/tests/Unit/Services/MediaMetadataServiceTest.php index 6955a51b..7ec2806f 100644 --- a/tests/Unit/Services/MediaMetadataServiceTest.php +++ b/tests/Unit/Services/MediaMetadataServiceTest.php @@ -34,12 +34,12 @@ class MediaMetadataServiceTest extends TestCase /** @var Album $album */ $album = factory(Album::class)->create(); $coverContent = 'dummy'; - $coverPath = '/koel/public/images/album/foo.jpg'; + $coverPath = '/koel/public/img/album/foo.jpg'; $this->imageWriter ->shouldReceive('writeFromBinaryData') ->once() - ->with('/koel/public/images/album/foo.jpg', 'dummy'); + ->with('/koel/public/img/album/foo.jpg', 'dummy'); $this->mediaMetadataService->writeAlbumCover($album, $coverContent, 'jpg', $coverPath); self::assertEquals(album_cover_url('foo.jpg'), Album::find($album->id)->cover); @@ -50,12 +50,12 @@ class MediaMetadataServiceTest extends TestCase /** @var Artist $artist */ $artist = factory(Artist::class)->create(); $imageContent = 'dummy'; - $imagePath = '/koel/public/images/artist/foo.jpg'; + $imagePath = '/koel/public/img/artist/foo.jpg'; $this->imageWriter ->shouldReceive('writeFromBinaryData') ->once() - ->with('/koel/public/images/artist/foo.jpg', 'dummy'); + ->with('/koel/public/img/artist/foo.jpg', 'dummy'); $this->mediaMetadataService->writeArtistImage($artist, $imageContent, 'jpg', $imagePath); self::assertEquals(artist_image_url('foo.jpg'), Artist::find($artist->id)->image); diff --git a/webpack.mix.js b/webpack.mix.js index 9aa52bd7..78cf2243 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -8,7 +8,7 @@ mix.webpackConfig({ plugins, output: { chunkFilename: mix.config.production ? 'js/[name].[chunkhash].js' : 'js/[name].js', - publicPath: '/public/' + publicPath: '/' }, devServer: { port: 8080, @@ -18,13 +18,9 @@ mix.webpackConfig({ } }) -mix.setResourceRoot('./public/') +mix.setResourceRoot('./') 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 {