1
0
mirror of https://github.com/robonen/metr.git synced 2026-03-20 02:44:42 +00:00

Merge pull request #14 from robonen/backend

Backend
This commit is contained in:
2022-06-01 23:33:56 +07:00
committed by GitHub
36 changed files with 784 additions and 28 deletions

View File

@@ -8,6 +8,5 @@ enum OrderTypesEnum: string
case HOUSE = 'House';
case FLAT = 'Flat';
case GUEST_HOUSE = 'Guest';
case HOTEL = 'Hotel';
case Land = 'Land';
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Enums;
enum RoomTypesEnum: string
{
use Arrayable;
case STUDIO = 'Studio';
case ROOM1 = 'Room1';
case Room2 = 'Room2';
case Room3More = 'Room3More';
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
trait Filterable
{
/**
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \App\Filters\QueryFilter $filters
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeFilter(Builder $builder, QueryFilter $filters): Builder
{
return $filters->apply($builder);
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace App\Filters;
use App\Enums\OrderTypesEnum;
use App\Enums\RoomTypesEnum;
use Illuminate\Database\Eloquent\Builder;
class OfferFilter extends QueryFilter
{
/**
* @param string $type
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function type(string $type): Builder
{
if (OrderTypesEnum::tryFrom($type) !== null)
return $this->builder->where('type', $type);
return $this->builder;
}
/**
* @param int $rooms
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function rooms(string $type): Builder
{
if (RoomTypesEnum::tryFrom($type) !== null)
return $this->builder->where('rooms', $type);
return $this->builder;
}
/**
* @param int $price
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function startPrice(int $price): Builder
{
if ($price >= 0)
return $this->builder->where('price', '>=', $price);
return $this->builder;
}
/**
* @param int $price
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function endPrice(int $price): Builder
{
if ($price >= 0)
return $this->builder->where('price', '<=', $price);
return $this->builder;
}
/**
* @param int $space
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function startSpace(int $space): Builder
{
if ($space >= 0)
return $this->builder->where('space', '>=', $space);
return $this->builder;
}
/**
* @param int $space
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function endSpace(int $space): Builder
{
if ($space >= 0)
return $this->builder->where('space', '<=', $space);
return $this->builder;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
abstract class QueryFilter
{
protected Request $request;
protected Builder $builder;
/**
* @param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Builder $builder): Builder
{
$this->builder = $builder;
foreach ($this->filters() as $name => $value) {
if (method_exists($this, $name)) {
call_user_func_array([$this, $name], array_filter([$value]));
}
}
return $this->builder;
}
/**
* @return array|string|null
*/
private function filters(): array|string|null
{
return $this->request->query();
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreFeedbackRequest;
use App\Http\Requests\UpdateFeedbackRequest;
use App\Http\Resources\FeedbackResource;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class FeedbackController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function index(): AnonymousResourceCollection
{
return FeedbackResource::collection(auth()->user()->feedback()->get());
}
/**
* Display the specified resource.
*
* @param int $id
* @return \App\Http\Resources\FeedbackResource
*/
public function show(int $id): FeedbackResource
{
$feedback = auth()->user()->feedback()->findOrFail($id);
return new FeedbackResource($feedback);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\StoreFeedbackRequest $request
* @return \App\Http\Resources\FeedbackResource
*/
public function store(StoreFeedbackRequest $request): FeedbackResource
{
$feedback = auth()->user()->feedback()->create($request->validated());
return new FeedbackResource($feedback);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\UpdateFeedbackRequest $request
* @param int $id
* @return void
*/
public function update(UpdateFeedbackRequest $request, int $id): void
{
$feedback = auth()->user()->feedback()->findOrFail($id);
$feedback->update($request->validated());
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return void
*/
public function destroy(int $id): void
{
auth()->user()->feedback()->findOrFail($id)->delete();
}
}

View File

@@ -2,10 +2,12 @@
namespace App\Http\Controllers;
use App\Filters\OfferFilter;
use App\Http\Requests\StoreOfferRequest;
use App\Http\Requests\UpdateOfferRequest;
use App\Http\Resources\OfferResource;
use App\Models\Offer;
use App\Models\OfferPhoto;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class OfferController extends Controller
@@ -13,11 +15,17 @@ class OfferController extends Controller
/**
* Display a listing of the resource.
*
* @param \App\Filters\OfferFilter $filters
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function index(): AnonymousResourceCollection
public function index(OfferFilter $filters): AnonymousResourceCollection
{
return OfferResource::collection(Offer::all());
return OfferResource::collection(
Offer::filter($filters)
->latest()
->with('images')
->get()
);
}
/**
@@ -28,8 +36,7 @@ class OfferController extends Controller
*/
public function show(int $id): OfferResource
{
$offer = Offer::findOrFail($id);
return new OfferResource($offer);
return new OfferResource(Offer::with(['images', 'user'])->findOrFail($id));
}
/**
@@ -40,7 +47,19 @@ class OfferController extends Controller
*/
public function store(StoreOfferRequest $request): OfferResource
{
return new OfferResource(Offer::create($request->validated()));
$data = $request->validated();
$images = $data['images'];
$offer = auth()->user()->offers()->create($data);
foreach ($images as $image)
{
$offer_photo = OfferPhoto::findOrFail($image['id']);
$offer_photo->offer_id = $offer->id;
$offer_photo->save();
}
return new OfferResource($offer);
}
/**
@@ -52,8 +71,18 @@ class OfferController extends Controller
*/
public function update(UpdateOfferRequest $request, int $id): void
{
$offer = Offer::findOrFail($id);
$offer->update($request->validated());
$data = $request->validated();
$images = $data['images'];
$offer = auth()->user()->offers()->findOrFail($id);
$offer->update($data);
foreach ($images as $image)
{
$offer_photo = OfferPhoto::findOrFail($image['id']);
$offer_photo->offer_id = $offer->id;
$offer_photo->save();
}
}
/**
@@ -67,4 +96,16 @@ class OfferController extends Controller
$offer = Offer::findOrFail($id);
$offer->delete();
}
public function allByUser(): AnonymousResourceCollection
{
return OfferResource::collection(
auth()
->user()
->offers()
->latest()
->with('images')
->get()
);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\UploadImageRequest;
use App\Http\Resources\UploadImageResource;
use App\Models\OfferPhoto;
use Illuminate\Support\Facades\Storage;
class UploadImageController extends Controller
{
/**
* @param \App\Http\Requests\UploadImageRequest $request
* @return \App\Http\Resources\UploadImageResource
*/
public function uploadCatalog(UploadImageRequest $request)
{
$image = $request->file('image')->store('public/offers');
$offer_photo = OfferPhoto::create([
'file' => $image,
]);
return new UploadImageResource($offer_photo);
}
public function deleteCatalog(int $id): void
{
$offer_photo = OfferPhoto::findOrFail($id);
if (Storage::exists($offer_photo->file))
Storage::delete($offer_photo->file);
$offer_photo->delete();
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Requests;
class StoreFeedbackRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'comment' => ['required', 'string', 'max:2000'],
'rating' => ['required', 'numeric', 'min:1', 'max:5'],
];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Requests;
use App\Enums\OrderTypesEnum;
use App\Enums\RoomTypesEnum;
use Illuminate\Validation\Rules\Enum;
class StoreOfferRequest extends BaseRequest
@@ -15,16 +16,16 @@ class StoreOfferRequest extends BaseRequest
public function rules(): array
{
return [
'user_id' => ['required', 'numeric', 'exists:users,id'],
'name' => ['required', 'string'],
'type' => ['required', new Enum(OrderTypesEnum::class)],
'price' => ['required', 'numeric', 'min:0.1'],
'rooms' => ['required', 'numeric', 'min:1'],
'rooms' => ['required', new Enum(RoomTypesEnum::class)],
'space' => ['required', 'numeric', 'min:1'],
'yandex_mark' => ['string'],
'location' => ['required', 'string'],
'description' => ['required', 'string'],
'is_group' => ['required', 'boolean'],
'images' => ['required', 'array'],
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Requests;
class UpdateFeedbackRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'comment' => ['string', 'max:2000'],
'rating' => ['numeric', 'min:1', 'max:5'],
];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Requests;
use App\Enums\OrderTypesEnum;
use App\Enums\RoomTypesEnum;
use Illuminate\Validation\Rules\Enum;
class UpdateOfferRequest extends BaseRequest
@@ -15,16 +16,16 @@ class UpdateOfferRequest extends BaseRequest
public function rules(): array
{
return [
'user_id' => ['numeric', 'exists:users,id'],
'name' => ['string'],
'type' => [new Enum(OrderTypesEnum::class)],
'price' => ['numeric', 'min:0.1'],
'rooms' => ['numeric', 'min:1'],
'rooms' => [new Enum(RoomTypesEnum::class)],
'space' => ['numeric', 'min:1'],
'yandex_mark' => ['string'],
'location' => ['string'],
'description' => ['string'],
'is_group' => ['boolean'],
'images' => ['array'],
];
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Requests;
class UploadImageRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'image' => ['required', 'image', 'mimes:jpg,png,jpeg', 'max:15000'],
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class FeedbackResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UploadImageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Feedback extends Model
{
@@ -19,4 +20,23 @@ class Feedback extends Model
'comment',
'rating',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'rating' => 'integer',
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
// public function user(): BelongsTo
// {
// return $this
// ->belongsTo(User::class)
// ->select('first_name');
// }
}

View File

@@ -3,12 +3,16 @@
namespace App\Models;
use App\Enums\OrderTypesEnum;
use App\Enums\RoomTypesEnum;
use App\Filters\Filterable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Offer extends Model
{
use HasFactory;
use HasFactory, Filterable;
/**
* The attributes that are mass assignable.
@@ -35,8 +39,28 @@ class Offer extends Model
*/
protected $casts = [
'type' => OrderTypesEnum::class,
'rooms' => RoomTypesEnum::class,
'space' => 'double',
'price' => 'double',
'is_group' => 'boolean',
];
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function images(): HasMany
{
return $this->hasMany(OfferPhoto::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user(): BelongsTo
{
return $this
->belongsTo(User::class)
->select('id','first_name', 'last_name', 'middle_name', 'phone', 'photo')
->with('feedback');
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
@@ -34,4 +35,14 @@ class User extends Authenticatable
protected $hidden = [
'password',
];
public function feedback(): HasMany
{
return $this->hasMany(Feedback::class);
}
public function offers(): HasMany
{
return $this->hasMany(Offer::class);
}
}

View File

@@ -29,6 +29,6 @@ return [
'max_age' => 0,
'supports_credentials' => false,
'supports_credentials' => true,
];

View File

@@ -1,6 +1,7 @@
<?php
use App\Enums\OrderTypesEnum;
use App\Enums\RoomTypesEnum;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
@@ -18,8 +19,8 @@ return new class extends Migration
$table->id();
$table->string('name');
$table->enum('type', OrderTypesEnum::values());
$table->decimal('price');
$table->unsignedSmallInteger('rooms');
$table->decimal('price', 15);
$table->enum('rooms', RoomTypesEnum::values());
$table->decimal('space');
$table->string('yandex_mark')->nullable();
$table->string('location');

View File

@@ -20,6 +20,7 @@ return new class extends Migration
$table
->foreignId('offer_id')
->nullable()
->constrained()
->onUpdate('cascade');
});

View File

@@ -3,7 +3,7 @@ version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
context: ./docker/8.1
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'

View File

@@ -0,0 +1,62 @@
FROM ubuntu:21.10
LABEL maintainer="Taylor Otwell"
ARG WWWGROUP
ARG NODE_VERSION=16
ARG POSTGRES_VERSION=14
WORKDIR /var/www/html
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update \
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 \
&& mkdir -p ~/.gnupg \
&& chmod 600 ~/.gnupg \
&& echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \
&& echo "keyserver hkp://keyserver.ubuntu.com:80" >> ~/.gnupg/dirmngr.conf \
&& gpg --recv-key 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c \
&& gpg --export 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c > /usr/share/keyrings/ppa_ondrej_php.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu impish main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
&& apt-get update \
&& apt-get install -y php7.4-cli php7.4-dev \
php7.4-pgsql php7.4-sqlite3 php7.4-gd \
php7.4-curl php7.4-memcached \
php7.4-imap php7.4-mysql php7.4-mbstring \
php7.4-xml php7.4-zip php7.4-bcmath php7.4-soap \
php7.4-intl php7.4-readline php7.4-pcov \
php7.4-msgpack php7.4-igbinary php7.4-ldap \
php7.4-redis php7.4-xdebug \
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarnkey.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt impish-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& apt-get update \
&& apt-get install -y yarn \
&& apt-get install -y mysql-client \
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php7.4
RUN groupadd --force -g $WWWGROUP sail
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
COPY start-container /usr/local/bin/start-container
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php/7.4/cli/conf.d/99-sail.ini
RUN chmod +x /usr/local/bin/start-container
EXPOSE 8000
ENTRYPOINT ["start-container"]

View File

@@ -0,0 +1,4 @@
[PHP]
post_max_size = 100M
upload_max_filesize = 100M
variables_order = EGPCS

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
if [ ! -z "$WWWUSER" ]; then
usermod -u $WWWUSER sail
fi
if [ ! -d /.composer ]; then
mkdir /.composer
fi
chmod -R ugo+rw /.composer
if [ $# -gt 0 ]; then
exec gosu $WWWUSER "$@"
else
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi

View File

@@ -0,0 +1,14 @@
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:php]
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80
user=sail
environment=LARAVEL_SAIL="1"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -0,0 +1,64 @@
FROM ubuntu:21.10
LABEL maintainer="Taylor Otwell"
ARG WWWGROUP
ARG NODE_VERSION=16
ARG POSTGRES_VERSION=14
WORKDIR /var/www/html
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update \
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 \
&& mkdir -p ~/.gnupg \
&& chmod 600 ~/.gnupg \
&& echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \
&& echo "keyserver hkp://keyserver.ubuntu.com:80" >> ~/.gnupg/dirmngr.conf \
&& gpg --recv-key 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c \
&& gpg --export 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c > /usr/share/keyrings/ppa_ondrej_php.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu impish main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
&& apt-get update \
&& apt-get install -y php8.0-cli php8.0-dev \
php8.0-pgsql php8.0-sqlite3 php8.0-gd \
php8.0-curl php8.0-memcached \
php8.0-imap php8.0-mysql php8.0-mbstring \
php8.0-xml php8.0-zip php8.0-bcmath php8.0-soap \
php8.0-intl php8.0-readline php8.0-pcov \
php8.0-msgpack php8.0-igbinary php8.0-ldap \
php8.0-redis php8.0-swoole php8.0-xdebug \
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarnkey.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt impish-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& apt-get update \
&& apt-get install -y yarn \
&& apt-get install -y mysql-client \
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN update-alternatives --set php /usr/bin/php8.0
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.0
RUN groupadd --force -g $WWWGROUP sail
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
COPY start-container /usr/local/bin/start-container
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php/8.0/cli/conf.d/99-sail.ini
RUN chmod +x /usr/local/bin/start-container
EXPOSE 8000
ENTRYPOINT ["start-container"]

View File

@@ -0,0 +1,4 @@
[PHP]
post_max_size = 100M
upload_max_filesize = 100M
variables_order = EGPCS

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
if [ ! -z "$WWWUSER" ]; then
usermod -u $WWWUSER sail
fi
if [ ! -d /.composer ]; then
mkdir /.composer
fi
chmod -R ugo+rw /.composer
if [ $# -gt 0 ]; then
exec gosu $WWWUSER "$@"
else
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi

View File

@@ -0,0 +1,14 @@
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:php]
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80
user=sail
environment=LARAVEL_SAIL="1"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -0,0 +1,63 @@
FROM ubuntu:22.04
LABEL maintainer="Taylor Otwell"
ARG WWWGROUP
ARG NODE_VERSION=16
ARG POSTGRES_VERSION=14
WORKDIR /var/www/html
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update \
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 \
&& mkdir -p ~/.gnupg \
&& chmod 600 ~/.gnupg \
&& echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \
&& echo "keyserver hkp://keyserver.ubuntu.com:80" >> ~/.gnupg/dirmngr.conf \
&& gpg --recv-key 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c \
&& gpg --export 0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c > /usr/share/keyrings/ppa_ondrej_php.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
&& apt-get update \
&& apt-get install -y php8.1-cli php8.1-dev \
php8.1-pgsql php8.1-sqlite3 php8.1-gd \
php8.1-curl \
php8.1-imap php8.1-mysql php8.1-mbstring \
php8.1-xml php8.1-zip php8.1-bcmath php8.1-soap \
php8.1-intl php8.1-readline \
php8.1-ldap \
php8.1-msgpack php8.1-igbinary php8.1-redis php8.1-swoole \
php8.1-memcached php8.1-pcov php8.1-xdebug \
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& apt-get update \
&& apt-get install -y yarn \
&& apt-get install -y mysql-client \
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.1
RUN groupadd --force -g $WWWGROUP sail
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
COPY start-container /usr/local/bin/start-container
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php/8.1/cli/conf.d/99-sail.ini
RUN chmod +x /usr/local/bin/start-container
EXPOSE 8000
ENTRYPOINT ["start-container"]

View File

@@ -0,0 +1,4 @@
[PHP]
upload_max_filesize = 15M
post_max_size = 16M
variables_order = EGPCS

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
if [ ! -z "$WWWUSER" ]; then
usermod -u $WWWUSER sail
fi
if [ ! -d /.composer ]; then
mkdir /.composer
fi
chmod -R ugo+rw /.composer
if [ $# -gt 0 ]; then
exec gosu $WWWUSER "$@"
else
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi

View File

@@ -0,0 +1,14 @@
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:php]
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80
user=sail
environment=LARAVEL_SAIL="1"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -3,8 +3,10 @@
use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\Auth\LogoutController;
use App\Http\Controllers\Auth\RegistrationController;
use App\Http\Controllers\FeedbackController;
use App\Http\Controllers\OfferController;
use App\Http\Controllers\OrderController;
use App\Http\Controllers\UploadImageController;
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;
@@ -32,16 +34,18 @@ Route::prefix('auth')->group(function() {
Route::middleware('auth:sanctum')->group(function() {
Route::prefix('user')->group(function() {
Route::get('', [UserController::class, 'index']);
Route::put('', [UserController::class, 'update']);
});
Route::apiResource('orders', OrderController::class);
Route::prefix('users')->group(function() {
Route::get('', [UserController::class, 'index']);
Route::put('', [UserController::class, 'update']);
Route::get('offers', [OfferController::class, 'allByUser']);
Route::apiResource('feedback', FeedbackController::class);
});
Route::apiResource('offers', OfferController::class);
// TODO: На главной странице 6 самых дорогих квартир
// TODO: Последние добавленные квартиры + фильтры
Route::post('offers/images', [UploadImageController::class, 'uploadCatalog']);
Route::delete('offers/images/{id}', [UploadImageController::class, 'deleteCatalog']);
});

View File

@@ -14,5 +14,6 @@ use Illuminate\Support\Facades\Route;
*/
//Route::get('/', function () {
// return view('welcome');
// phpinfo();
//// return view('welcome');
//});