diff --git a/backend/app/Enums/OrderTypesEnum.php b/backend/app/Enums/OrderTypesEnum.php index 6ae3c41..64f7224 100644 --- a/backend/app/Enums/OrderTypesEnum.php +++ b/backend/app/Enums/OrderTypesEnum.php @@ -8,6 +8,5 @@ enum OrderTypesEnum: string case HOUSE = 'House'; case FLAT = 'Flat'; - case GUEST_HOUSE = 'Guest'; - case HOTEL = 'Hotel'; + case Land = 'Land'; } diff --git a/backend/app/Enums/RoomTypesEnum.php b/backend/app/Enums/RoomTypesEnum.php new file mode 100644 index 0000000..cf41e7a --- /dev/null +++ b/backend/app/Enums/RoomTypesEnum.php @@ -0,0 +1,13 @@ +apply($builder); + } +} diff --git a/backend/app/Filters/OfferFilter.php b/backend/app/Filters/OfferFilter.php new file mode 100644 index 0000000..5a9ae7b --- /dev/null +++ b/backend/app/Filters/OfferFilter.php @@ -0,0 +1,82 @@ +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; + } +} diff --git a/backend/app/Filters/QueryFilter.php b/backend/app/Filters/QueryFilter.php new file mode 100644 index 0000000..f55ad87 --- /dev/null +++ b/backend/app/Filters/QueryFilter.php @@ -0,0 +1,46 @@ +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(); + } +} diff --git a/backend/app/Http/Controllers/FeedbackController.php b/backend/app/Http/Controllers/FeedbackController.php new file mode 100644 index 0000000..1cf93d8 --- /dev/null +++ b/backend/app/Http/Controllers/FeedbackController.php @@ -0,0 +1,69 @@ +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(); + } +} diff --git a/backend/app/Http/Controllers/OfferController.php b/backend/app/Http/Controllers/OfferController.php index 7ab8e53..48b66e3 100644 --- a/backend/app/Http/Controllers/OfferController.php +++ b/backend/app/Http/Controllers/OfferController.php @@ -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() + ); + } } diff --git a/backend/app/Http/Controllers/UploadImageController.php b/backend/app/Http/Controllers/UploadImageController.php new file mode 100644 index 0000000..cf99d4b --- /dev/null +++ b/backend/app/Http/Controllers/UploadImageController.php @@ -0,0 +1,36 @@ +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(); + } +} diff --git a/backend/app/Http/Requests/StoreFeedbackRequest.php b/backend/app/Http/Requests/StoreFeedbackRequest.php new file mode 100644 index 0000000..abbf80e --- /dev/null +++ b/backend/app/Http/Requests/StoreFeedbackRequest.php @@ -0,0 +1,19 @@ + + */ + public function rules() + { + return [ + 'comment' => ['required', 'string', 'max:2000'], + 'rating' => ['required', 'numeric', 'min:1', 'max:5'], + ]; + } +} diff --git a/backend/app/Http/Requests/StoreOfferRequest.php b/backend/app/Http/Requests/StoreOfferRequest.php index 15615dd..558032b 100644 --- a/backend/app/Http/Requests/StoreOfferRequest.php +++ b/backend/app/Http/Requests/StoreOfferRequest.php @@ -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'], ]; } } diff --git a/backend/app/Http/Requests/UpdateFeedbackRequest.php b/backend/app/Http/Requests/UpdateFeedbackRequest.php new file mode 100644 index 0000000..3b1a355 --- /dev/null +++ b/backend/app/Http/Requests/UpdateFeedbackRequest.php @@ -0,0 +1,19 @@ + + */ + public function rules() + { + return [ + 'comment' => ['string', 'max:2000'], + 'rating' => ['numeric', 'min:1', 'max:5'], + ]; + } +} diff --git a/backend/app/Http/Requests/UpdateOfferRequest.php b/backend/app/Http/Requests/UpdateOfferRequest.php index 4e0903e..d48895c 100644 --- a/backend/app/Http/Requests/UpdateOfferRequest.php +++ b/backend/app/Http/Requests/UpdateOfferRequest.php @@ -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'], ]; } } diff --git a/backend/app/Http/Requests/UploadImageRequest.php b/backend/app/Http/Requests/UploadImageRequest.php new file mode 100644 index 0000000..654b390 --- /dev/null +++ b/backend/app/Http/Requests/UploadImageRequest.php @@ -0,0 +1,18 @@ + + */ + public function rules() + { + return [ + 'image' => ['required', 'image', 'mimes:jpg,png,jpeg', 'max:15000'], + ]; + } +} diff --git a/backend/app/Http/Resources/FeedbackResource.php b/backend/app/Http/Resources/FeedbackResource.php new file mode 100644 index 0000000..6fb29be --- /dev/null +++ b/backend/app/Http/Resources/FeedbackResource.php @@ -0,0 +1,19 @@ + + */ + protected $casts = [ + 'rating' => 'integer', + ]; + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ +// public function user(): BelongsTo +// { +// return $this +// ->belongsTo(User::class) +// ->select('first_name'); +// } } diff --git a/backend/app/Models/Offer.php b/backend/app/Models/Offer.php index edb7327..d5e530b 100644 --- a/backend/app/Models/Offer.php +++ b/backend/app/Models/Offer.php @@ -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'); + } } diff --git a/backend/app/Models/User.php b/backend/app/Models/User.php index 0dd1542..75a3954 100644 --- a/backend/app/Models/User.php +++ b/backend/app/Models/User.php @@ -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); + } } diff --git a/backend/config/cors.php b/backend/config/cors.php index 8a39e6d..94f07be 100644 --- a/backend/config/cors.php +++ b/backend/config/cors.php @@ -29,6 +29,6 @@ return [ 'max_age' => 0, - 'supports_credentials' => false, + 'supports_credentials' => true, ]; diff --git a/backend/database/migrations/2022_05_26_030738_create_offers_table.php b/backend/database/migrations/2022_05_26_030738_create_offers_table.php index 186ccf1..2385de9 100644 --- a/backend/database/migrations/2022_05_26_030738_create_offers_table.php +++ b/backend/database/migrations/2022_05_26_030738_create_offers_table.php @@ -1,6 +1,7 @@ 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'); diff --git a/backend/database/migrations/2022_05_26_035738_create_offer_photos_table.php b/backend/database/migrations/2022_05_26_035738_create_offer_photos_table.php index 4022a15..bd31bb4 100644 --- a/backend/database/migrations/2022_05_26_035738_create_offer_photos_table.php +++ b/backend/database/migrations/2022_05_26_035738_create_offer_photos_table.php @@ -20,6 +20,7 @@ return new class extends Migration $table ->foreignId('offer_id') + ->nullable() ->constrained() ->onUpdate('cascade'); }); diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index e3067be..d21d912 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -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}' diff --git a/backend/docker/7.4/Dockerfile b/backend/docker/7.4/Dockerfile new file mode 100644 index 0000000..cc500ce --- /dev/null +++ b/backend/docker/7.4/Dockerfile @@ -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"] diff --git a/backend/docker/7.4/php.ini b/backend/docker/7.4/php.ini new file mode 100644 index 0000000..66d04d5 --- /dev/null +++ b/backend/docker/7.4/php.ini @@ -0,0 +1,4 @@ +[PHP] +post_max_size = 100M +upload_max_filesize = 100M +variables_order = EGPCS diff --git a/backend/docker/7.4/start-container b/backend/docker/7.4/start-container new file mode 100644 index 0000000..b99ddd0 --- /dev/null +++ b/backend/docker/7.4/start-container @@ -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 diff --git a/backend/docker/7.4/supervisord.conf b/backend/docker/7.4/supervisord.conf new file mode 100644 index 0000000..9d28479 --- /dev/null +++ b/backend/docker/7.4/supervisord.conf @@ -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 diff --git a/backend/docker/8.0/Dockerfile b/backend/docker/8.0/Dockerfile new file mode 100644 index 0000000..096adad --- /dev/null +++ b/backend/docker/8.0/Dockerfile @@ -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"] diff --git a/backend/docker/8.0/php.ini b/backend/docker/8.0/php.ini new file mode 100644 index 0000000..66d04d5 --- /dev/null +++ b/backend/docker/8.0/php.ini @@ -0,0 +1,4 @@ +[PHP] +post_max_size = 100M +upload_max_filesize = 100M +variables_order = EGPCS diff --git a/backend/docker/8.0/start-container b/backend/docker/8.0/start-container new file mode 100644 index 0000000..b99ddd0 --- /dev/null +++ b/backend/docker/8.0/start-container @@ -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 diff --git a/backend/docker/8.0/supervisord.conf b/backend/docker/8.0/supervisord.conf new file mode 100644 index 0000000..9d28479 --- /dev/null +++ b/backend/docker/8.0/supervisord.conf @@ -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 diff --git a/backend/docker/8.1/Dockerfile b/backend/docker/8.1/Dockerfile new file mode 100644 index 0000000..0277709 --- /dev/null +++ b/backend/docker/8.1/Dockerfile @@ -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"] diff --git a/backend/docker/8.1/php.ini b/backend/docker/8.1/php.ini new file mode 100644 index 0000000..bf782b2 --- /dev/null +++ b/backend/docker/8.1/php.ini @@ -0,0 +1,4 @@ +[PHP] +upload_max_filesize = 15M +post_max_size = 16M +variables_order = EGPCS diff --git a/backend/docker/8.1/start-container b/backend/docker/8.1/start-container new file mode 100644 index 0000000..b99ddd0 --- /dev/null +++ b/backend/docker/8.1/start-container @@ -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 diff --git a/backend/docker/8.1/supervisord.conf b/backend/docker/8.1/supervisord.conf new file mode 100644 index 0000000..9d28479 --- /dev/null +++ b/backend/docker/8.1/supervisord.conf @@ -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 diff --git a/backend/routes/api.php b/backend/routes/api.php index 42ae39e..51f73ea 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -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); + + Route::post('offers/images', [UploadImageController::class, 'uploadCatalog']); + Route::delete('offers/images/{id}', [UploadImageController::class, 'deleteCatalog']); }); -Route::apiResource('offers', OfferController::class); - -// TODO: На главной странице 6 самых дорогих квартир -// TODO: Последние добавленные квартиры + фильтры diff --git a/backend/routes/web.php b/backend/routes/web.php index edd263d..652982b 100644 --- a/backend/routes/web.php +++ b/backend/routes/web.php @@ -14,5 +14,6 @@ use Illuminate\Support\Facades\Route; */ //Route::get('/', function () { -// return view('welcome'); +// phpinfo(); +//// return view('welcome'); //});