digitalbiblesociety/dbp

View on GitHub
app/Http/Controllers/Organization/ProjectsController.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace App\Http\Controllers\Organization;

use App\Http\Controllers\APIController;
use App\Models\User\Key;
use App\Models\User\Project;
use App\Models\User\ProjectMember;
use App\Models\User\Role;
use Illuminate\Http\Request;
use App\Transformers\ProjectTransformer;

use Illuminate\View\View;
use \Illuminate\Http\Response;
use Validator;

class ProjectsController extends APIController
{
    /**
     * Display a listing of the resource.
     *
     * @OA\Get(
     *     path="/projects",
     *     tags={"Users"},
     *     summary="Returns the projects currently using the DBP",
     *     description="Returns the projects currently registered that aren't labeled as sensitive",
     *     operationId="v4_projects.index",
     *     @OA\Parameter(ref="#/components/parameters/version_number"),
     *     @OA\Parameter(ref="#/components/parameters/key"),
     *     @OA\Parameter(ref="#/components/parameters/pretty"),
     *     @OA\Parameter(ref="#/components/parameters/format"),
     *     @OA\Response(
     *         response=200,
     *         description="successful operation",
     *         @OA\MediaType(mediaType="application/json", @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="application/xml",  @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="text/x-yaml",      @OA\Schema(ref="#/components/schemas/v4_projects_index"))
     *     )
     * )
     *
     * @return Response
     */
    public function index()
    {
        if (!$this->api) {
            return view('community.projects.index');
        }
        $projects = Project::where('sensitive', 0)->get();
        return $this->reply(fractal($projects, ProjectTransformer::class));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    {
        return view('dashboard.projects.create');
    }


    /**
     * Store a new Project
     *
     * @OA\Post(
     *     path="/projects",
     *     tags={"Users"},
     *     summary="Apply for a project_id",
     *     description="It is recommended that you create a distinct project_id for each app using the API",
     *     operationId="v4_projects.store",
     *     @OA\Parameter(ref="#/components/parameters/version_number"),
     *     @OA\Parameter(ref="#/components/parameters/key"),
     *     @OA\Parameter(ref="#/components/parameters/pretty"),
     *     @OA\Parameter(ref="#/components/parameters/format"),
     *     @OA\RequestBody(required=true, description="Information supplied for user creation", @OA\MediaType(mediaType="application/json",
     *          @OA\Schema(
     *              @OA\Property(property="name",                    ref="#/components/schemas/Project/properties/name"),
     *              @OA\Property(property="url_avatar",              ref="#/components/schemas/Project/properties/url_avatar"),
     *              @OA\Property(property="url_avatar_icon",         ref="#/components/schemas/Project/properties/url_avatar_icon"),
     *              @OA\Property(property="url_site",                ref="#/components/schemas/Project/properties/url_site"),
     *              @OA\Property(property="description",             ref="#/components/schemas/Project/properties/description")
     *          )
     *     )),
     *     @OA\Response(
     *         response=200,
     *         description="successful operation",
     *         @OA\MediaType(mediaType="application/json", @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="application/xml",  @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="text/x-yaml",      @OA\Schema(ref="#/components/schemas/v4_projects_index"))
     *     )
     * )
     *
     * @param Request $request
     *
     * @return View|\Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $user = \Auth::user() ?? $this->user;
        if (!$user) {
            return $this->setStatusCode(401)->replyWithError(trans('api.auth_permission_denied'));
        }
        $this->validateProject($request);

        $project = \DB::transaction(function () use ($request, $user) {
            $project = Project::create([
                'id'              => random_int(1, 65535),
                'name'            => $request->name,
                'url_avatar'      => $request->url_avatar,
                'url_avatar_icon' => $request->url_avatar_icon,
                'url_site'        => $request->url_site,
                'description'     => $request->description,
            ]);
            $admin_role = Role::where('slug', 'admin')->first();
            if (!$admin_role) {
                return $this->replyWithError('No Admin Role Found');
            }
            $developer_role = Role::where('slug', 'developer')->first();
            if (!$developer_role) {
                return $this->replyWithError('No Developer Role Found');
            }
            $project->members()->create([
                'user_id' => $user->id,
                'role_id' => $admin_role->id
            ], [
                'user_id' => $user->id,
                'role_id' => $developer_role->id
            ]);

            return $project;
        });

        if (!$this->api) {
            return view('dashboard.projects.show', compact('user', 'project'));
        }
        return $this->setStatusCode(200)->reply(fractal($project, ProjectTransformer::class)->addMeta(['message' => trans('api.projects_created_200')]));
    }

    /**
     * Display the specified resource.
     *
     * @OA\Get(
     *     path="/projects/{project_id}",
     *     tags={"Users"},
     *     summary="Get the details for a project",
     *     description="",
     *     operationId="v4_projects.show",
     *     @OA\Parameter(name="project_id", in="path", required=true, description="The project id", @OA\Schema(ref="#/components/schemas/Project/properties/id")),
     *     @OA\Parameter(ref="#/components/parameters/version_number"),
     *     @OA\Parameter(ref="#/components/parameters/key"),
     *     @OA\Parameter(ref="#/components/parameters/pretty"),
     *     @OA\Parameter(ref="#/components/parameters/format"),
     *     @OA\Response(
     *         response=200,
     *         description="successful operation",
     *         @OA\MediaType(mediaType="application/json", @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="application/xml",  @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="text/x-yaml",      @OA\Schema(ref="#/components/schemas/v4_projects_index"))
     *     )
     * )
     *
     * @param  int $id
     *
     * @return View|Response
     */
    public function show($id)
    {
        $access_allowed = true;
        $user           = \Auth::user() ?? $this->user;

        $project = Project::find($id);
        if (!$project) {
            return $this->setStatusCode(404)->replyWithError(trans('api.projects_404'));
        }

        if ($project->sensitive) {
            $access_allowed = $user !== null ? ($project->members->contains($user) or $user->admin) : false;
        }
        if (!$access_allowed) {
            return $this->setStatusCode(404)->replyWithError(trans('api.projects_401'));
        }

        if (!$this->api) {
            return view('community.projects.show', compact('project'));
        }
        return $this->reply(fractal($project, ProjectTransformer::class));
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int $id
     *
     * @return Response
     */
    public function edit($id)
    {
        $project = Project::where('id', $id)->first();
        return view('dashboard.projects.edit', compact('project'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @OA\Put(
     *     path="/projects/{project_id}",
     *     tags={"Users"},
     *     summary="Update the details for a project",
     *     description="",
     *     operationId="v4_projects.update",
     *     @OA\Parameter(name="project_id", in="path", required=true, description="The project id", @OA\Schema(ref="#/components/schemas/Project/properties/id")),
     *     @OA\Parameter(ref="#/components/parameters/version_number"),
     *     @OA\Parameter(ref="#/components/parameters/key"),
     *     @OA\Parameter(ref="#/components/parameters/pretty"),
     *     @OA\Parameter(ref="#/components/parameters/format"),
     *     @OA\Response(
     *         response=200,
     *         description="successful operation",
     *         @OA\MediaType(mediaType="application/json", @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="application/xml",  @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="text/x-yaml",      @OA\Schema(ref="#/components/schemas/v4_projects_index"))
     *     )
     * )
     *
     * @param  \Illuminate\Http\Request $request
     * @param  int $id
     *
     * @return Response
     */
    public function update(Request $request, $id)
    {
        $user = $this->user;
        if (!$user) {
            return $this->setStatusCode(401)->replyWithError("you're not logged in");
        }
        $this->validateProject($request);

        $project = Project::find($id);
        if (!$project) {
            return $this->setStatusCode(404)->replyWithError(trans('api.projects_404'));
        }
        $access_allowed = $project->developers;
        if (!$access_allowed) {
            return $this->setStatusCode(404)->replyWithError(trans('api.projects_401'));
        }

        $project->update($request->all());
        $project->save();

        return $this->setStatusCode(200)->reply(fractal($project, ProjectTransformer::class)->addMeta(['message' => trans('api.projects_updated_200')]));
    }

    /**
     * Remove the specified resource from storage.
     *
     * @OA\Delete(
     *     path="/projects/{project_id}",
     *     tags={"Users"},
     *     summary="Remove a project",
     *     description="",
     *     operationId="v4_projects.destroy",
     *     @OA\Parameter(name="project_id", in="path", required=true, description="The project id", @OA\Schema(ref="#/components/schemas/Project/properties/id")),
     *     @OA\Parameter(ref="#/components/parameters/version_number"),
     *     @OA\Parameter(ref="#/components/parameters/key"),
     *     @OA\Parameter(ref="#/components/parameters/pretty"),
     *     @OA\Parameter(ref="#/components/parameters/format"),
     *     @OA\Response(
     *         response=200,
     *         description="successful operation",
     *         @OA\MediaType(mediaType="application/json", @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="application/xml",  @OA\Schema(ref="#/components/schemas/v4_projects_index")),
     *         @OA\MediaType(mediaType="text/x-yaml",      @OA\Schema(ref="#/components/schemas/v4_projects_index"))
     *     )
     * )
     *
     * @param  int $id
     *
     * @return Response
     */
    public function destroy($id)
    {
        $project = Project::find($id);
        if (!$project) {
            return $this->setStatusCode(404)->replyWithError(trans('api.projects_404'));
        }

        $access_allowed = $project->admins->where('user_id', $this->user->id)->first();
        if (!$access_allowed) {
            return $this->setStatusCode(401)->replyWithError(trans('api.projects_destroy_401'));
        }

        $project->delete();
        return $this->setStatusCode(200)->reply(trans('api.projects_destroy_200'));
    }


    /**
     * Validate Requests to Connect Users to Projects
     *
     * @param $token
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function connect($token)
    {
        $project_member = ProjectMember::with('project')->where('token', $token)->first();
        if (!$project_member) {
            return $this->setStatusCode(404)->replyWithError(trans('api.project_errors_member_404'));
        }

        $project_member->subscribed = true;
        $project_member->save();

        return redirect()->away($project_member->project->url_site);
    }


    /**
     * Validate Requests to Connect Users to Projects
     *
     * @param $request
     *
     * @return Response|\Illuminate\Http\RedirectResponse|null
     */
    private function validateProject(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id'   => ($request->method() === 'POST') ? 'required|unique:dbp_users.projects,id|max:24' : 'required|exists:dbp_users.projects,id|max:24',
            'name' => 'required',
        ]);

        if ($validator->fails()) {
            if ($this->api) {
                return $this->setStatusCode(422)->replyWithError($validator->errors());
            }
            if (!$this->api) {
                return redirect('dashboard/projects/create')->withErrors($validator)->withInput();
            }
        }

        return null;
    }
}