badgeteam/Hatchery

View on GitHub
app/Http/Controllers/FilesController.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Requests\FileStoreRequest;
use App\Http\Requests\FileUpdateRequest;
use App\Http\Requests\FileUploadRequest;
use App\Jobs\LintContent;
use App\Jobs\ProcessFile;
use App\Models\File;
use App\Models\Version;
use App\Support\Linters;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\UploadedFile;
use Illuminate\View\View;

/**
 * Class FilesController.
 *
 * @author annejan@badge.team
 */
class FilesController extends Controller
{
    /**
     * Create a new controller instance.
     */
    public function __construct()
    {
        $this->middleware('auth', ['except' => ['show', 'download']]);
        $this->authorizeResource(File::class, null, ['except' => ['show', 'download']]);
    }

    /**
     * Display a listing of the resource.
     *
     * @param Version           $version
     * @param FileUploadRequest $request
     */
    public function upload(Version $version, FileUploadRequest $request): void
    {
        /** @var UploadedFile $upload */
        $upload = $request->file('file');
        /** @var File $file */
        $file = $version->files()->firstOrNew(['name' => $upload->getClientOriginalName()]);
        $file->content = (string) file_get_contents($upload->path());
        $file->save();
        LintContent::dispatch($file);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param File $file
     *
     * @return View
     */
    public function edit(File $file): View
    {
        return view('files.edit')
            ->with('file', $file);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param FileUpdateRequest $request
     * @param File              $file
     *
     * @return RedirectResponse
     */
    public function update(FileUpdateRequest $request, File $file): RedirectResponse
    {
        try {
            $file->content = $request->file_content;
            $file->save();
        } catch (\Exception $e) {
            return redirect()->route('files.edit', ['file' => $file->id])
                ->withInput()->withErrors([$e->getMessage()]);
        }

        if ($file->lintable) {
            $data = Linters::lintFile($file);
            if ($data['return_value'] === 0) {
                return redirect()
                    ->route('projects.edit', ['project' => $file->version->project])
                    ->withSuccesses([$file->name . ' saved']);
            }

            if (!empty($data[0])) {
                return redirect()->route('files.edit', ['file' => $file->id])
                    ->withInput()
                    ->withSuccesses([$file->name . ' saved'])
                    ->withWarnings(explode("\n", (string) $data[0]));
            }

            return redirect()->route('files.edit', ['file' => $file->id])
                ->withInput()
                ->withSuccesses([$file->name . ' saved'])
                ->withErrors(explode("\n", (string) $data[1]));
        }

        return redirect()
            ->route('projects.edit', ['project' => $file->version->project])
            ->withSuccesses([$file->name . ' saved']);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @param Request $request
     *
     * @return View
     */
    public function create(Request $request): View
    {
        $version = Version::where('id', $request->get('version'))->firstOrFail();

        return view('files.create')
            ->with('version', $version)
            ->with('name', $request->name);
    }

    /**
     * @param Request $request
     *
     * @return RedirectResponse
     */
    public function createIcon(Request $request): RedirectResponse
    {
        /** @var Version $version */
        $version = Version::where('id', $request->get('version'))->firstOrFail();
        $file = new File();
        $pixels = [];
        for ($p = 0; $p < 64; $p++) {
            $pixels[] = '0x00000000';
        }

        try {
            $file->version_id = $version->id;
            $file->name = $request->has('name') ? $request->get('name') : 'icon.py';
            $file->content = 'icon = ([' . implode(', ', $pixels) . '], 1)';
            $file->save();
        } catch (\Exception $e) {
            return redirect()->route(
                'projects.edit',
                [
                'project' => $version->project]
            )->withInput()->withErrors([$e->getMessage()
                    ]);
        }

        return redirect()->route('files.edit', ['file' => $file->id])->withSuccesses([$file->name . ' created']);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param FileStoreRequest $request
     *
     * @return RedirectResponse
     */
    public function store(FileStoreRequest $request): RedirectResponse
    {
        $file = new File();

        try {
            $file->version_id = $request->version_id;
            $file->name = $request->name;
            $file->content = $request->file_content;
            $file->save();
            LintContent::dispatch($file);
        } catch (\Exception $e) {
            return redirect()->route('files.create')->withInput()->withErrors([$e->getMessage()]);
        }

        return redirect()->route(
            'projects.edit',
            [
            'project' => $file->version->project]
        )->withSuccesses([$file->name . ' saved'
                ]);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param File $file
     *
     * @return RedirectResponse
     */
    public function destroy(File $file): RedirectResponse
    {
        $project = $file->version->project;

        try {
            $file->delete();
        } catch (\Exception $e) {
            return redirect(URL()->previous())
                ->withInput()
                ->withErrors([$e->getMessage()]);
        }

        return redirect()->route('projects.edit', ['project' => $project])->withSuccesses([$file->name . ' deleted']);
    }

    /**
     * Show file content, public method ツ.
     *
     * @param File $file
     *
     * @return View
     */
    public function show(File $file): View
    {
        return view('files.show')
            ->with('file', $file);
    }

    /**
     * Download file content, public method ツ what could go wrong..
     *
     * @param File $file
     *
     * @return Response
     */
    public function download(File $file): Response
    {
        return response($file->content)
            ->header('Cache-Control', 'no-cache private')
            ->header('Content-Description', 'File Transfer')
            ->header('Content-Type', $file->mime)
            ->header('Content-length', (string) strlen($file->content))
            ->header('Content-Disposition', 'attachment; filename=' . $file->name)
            ->header('Content-Transfer-Encoding', 'binary');
    }

    /**
     * @param FileUpdateRequest $request
     * @param File              $file
     *
     * @return JsonResponse
     */
    public function lint(FileUpdateRequest $request, File $file): JsonResponse
    {
        LintContent::dispatch($file, $request->file_content);

        return response()->json(['linting' => 'started']);
    }

    /**
     * @param File $file
     *
     * @return JsonResponse
     */
    public function process(File $file): JsonResponse
    {
        ProcessFile::dispatch($file);

        return response()->json(['processing' => 'started']);
    }
}