Последняя версия с сервера прошлого разработчика

This commit is contained in:
2025-07-10 04:35:51 +00:00
commit c731570032
1174 changed files with 134314 additions and 0 deletions

66
.env.example Executable file
View File

@@ -0,0 +1,66 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
FRONTEND_URL=https://dev.teeaseer.com
WWWGROUP=1000
WWWUSER=1000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
FILESYSTEM_DRIVER=public
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
MAIL_ADMIN_EMAIL=mail@4teaser.com
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
INTERKASSA_AUTH_KEY=
INTERKASSA_ACCOUNT_ID=
INTERKASSA_SECRET_KEY=
INTERKASSA_ID=
QIWI_PUBLIC=
QIWI_SECRET=
YOOKASSA_SHOP_ID=
YOOKASSA_KEY=

2
.eslintignore Executable file
View File

@@ -0,0 +1,2 @@
dist
public

58
.eslintrc.js vendored Executable file
View File

@@ -0,0 +1,58 @@
module.exports = {
'globals': {
'defineProps': 'readonly',
'defineEmits': 'readonly',
'defineExpose': 'readonly',
'withDefaults': 'readonly'
},
'env': {
'browser': true,
'node': true,
'es2021': true
},
'extends': [
'eslint:recommended',
'plugin:vue/vue3-recommended'
],
'parserOptions': {
'ecmaVersion': 13,
'sourceType': 'module'
},
'plugins': [
'vue'
],
'rules': {
'indent': [
'error',
4
],
'linebreak-style': [
'error',
'windows'
],
'quotes': [
'error',
'single'
],
'semi': [
'error',
'never'
],
// 'no-unused-vars': 'off',
'no-undef': 'off',
'vue/html-self-closing': 'off',
'vue/no-v-html': 'off',
'vue/max-attributes-per-line': ['error', {
'singleline': {
'max': 2,
'allowFirstLine': true
},
'multiline': {
'max': 2,
'allowFirstLine': true
}
}]
}
}

5
.gitattributes vendored Executable file
View File

@@ -0,0 +1,5 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore

42
.gitignore vendored Executable file
View File

@@ -0,0 +1,42 @@
/node_modules
/public/css
/public/hot
/public/js
/public/mix-manifest.json
/public/storage
/public/dist
/storage/*.key
.DS_Store
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
note.md
*.log
.DS_Store
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/.fleet
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
Homestead.json
Homestead.yaml
Thumbs.db
# что за хуйня здесь происходит?
# то что выше переделать потом
.env

21
.php-cs-fixer.dist.php Executable file
View File

@@ -0,0 +1,21 @@
<?php
// Reference: http://cs.sensiolabs.org/
return PhpCsFixer\Config::create()
->setUsingCache(false)
->setRiskyAllowed(true)
->setRules([
'@PHP70Migration' => true,
'@PHP71Migration' => true,
'@PSR2' => true,
// '@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'increment_style' => ['style' => 'post'],
'no_multiline_whitespace_before_semicolons' => true,
'not_operator_with_successor_space' => true,
'ordered_imports' => ['sortAlgorithm' => 'alpha'],
'semicolon_after_instruction' => false,
'strict_comparison' => true,
'yoda_style' => false,
]);

13
.styleci.yml Executable file
View File

@@ -0,0 +1,13 @@
php:
preset: laravel
disabled:
- no_unused_imports
finder:
not-name:
- index.php
- server.php
js:
finder:
not-name:
- webpack.mix.js
css: true

62
README.md Executable file
View File

@@ -0,0 +1,62 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
<p align="center">
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
## About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
## Laravel Sponsors
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
### Premium Partners
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Code of Conduct
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

View File

@@ -0,0 +1,92 @@
<?php
namespace App\Console\Commands;
use DB;
use Carbon\Carbon;
use Illuminate\Console\Command;
use App\Domain\Points\Models\Point;
use App\Domain\Points\Enums\DirectionEnum;
use App\Domain\Subscriptions\Models\Package;
use App\Domain\Subscriptions\Models\Subscription;
use App\Domain\Subscriptions\Service\SubscriptionService;
class AutoSubscribeApp extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'teaser:auto-subs-app';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Autosubscription to the site';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$plan = Package::findOrFail(1);
$price = $plan->price;
$lists = DB::table('subscriptions')
->join('users', 'subscriptions.user_id', '=', 'users.id')
->selectRaw('subscriptions.user_id, MAX(subscriptions.ends_at) as last_time, users.autosubscription_site')
->groupBy('subscriptions.user_id', 'users.autosubscription_site')
->havingRaw('MAX(subscriptions.ends_at) <= ?', [now()])
->having('users.autosubscription_site', true)
->get();
foreach($lists as $list){
$balance = SubscriptionService::calculate($list->user_id);
$ends_at = Carbon::now()->addMonths();
if ($price > $balance) {
echo 'Недостаточно средств ' . $list->user_id . PHP_EOL;
DB::table('users')
->where('id', $list->user_id)
->update(['autosubscription_site' => false]);
continue;
}
$sub = new Subscription;
$sub->user_id = $list->user_id;
$sub->package_id = $plan->id;
$sub->price = $price;
$sub->ends_at = $ends_at;
$sub->status = 'complete'; //YSV ENUM!
$sub->save();
$point = new Point;
$point->user_id =$list->user_id;
$point->point = $price;
$point->type = 'Оплата за подписку'; //YSV ENUM!
$point->direction = DirectionEnum::EXPENSE();
$point->save();
}
return 0;
}
}

View File

@@ -0,0 +1,182 @@
<?php
namespace App\Console\Commands;
use DB;
use App\Models\User;
use Illuminate\Console\Command;
use App\Domain\Points\Models\Point;
use App\Domain\Users\Models\UserPackage;
use App\Domain\Points\Enums\DirectionEnum;
use App\Notifications\UserCustomPaidSubscription;
use App\Domain\Subscriptions\Service\SubscriptionService;
class AutoSubscribePaidUsers extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'teaser:user-auto-subs';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Auto-subscription for paid users';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
\DB::beginTransaction();
$users_package_customers = DB::table('users_package_customers')
// ->join('users_subscribers', 'users_package_customers.customer_id', '=', 'users_subscribers.subscriber_id')
->join('users_subscribers', function ($join) {
$join
->on('users_package_customers.user_id', '=', 'users_subscribers.subscriber_id')
->where('users_subscribers.autosubscription', true);
})
//->select('users_package_customers.*', 'users_subscribers.user_id as userId', 'users_subscribers.subscriber_id as subscriberId', 'users_subscribers.autosubscription')
->select(DB::raw('MAX(users_package_customers.time_end) as last_time,users_package_customers.customer_id,users_package_customers.package_id','users_subscribers.autosubscription'))
->groupBy('users_package_customers.customer_id', 'users_package_customers.package_id', 'users_subscribers.autosubscription')
->havingRaw('MAX(users_package_customers.time_end) <= ?', [now()])
->get();
foreach ($users_package_customers as $user_package_customers) {
$userCustomer = User::find($user_package_customers->customer_id);
$userPackage = UserPackage::find($user_package_customers->package_id);
$userHeadPackage = User::find($userPackage->user_id);
$balance = SubscriptionService::calculate($userCustomer->id);
if ($userPackage->price > $balance) {
DB::table('users_subscribers')
->where('user_id', $userCustomer->id)
->where('subscriber_id', $userHeadPackage->id)
->update(['autosubscription' => DB::raw('NOT autosubscription')]);
continue;
}
DB::table('users_package_customers')->insert([
'user_id' => $userHeadPackage->id,
'customer_id' => $userCustomer->id,
'package_id' => $userPackage->id,
'price' => $userPackage->price,
'time_end' => now()->addMonths(),
//'time_end' => now()->addMinutes(10),
'created_at' => now(),
]);
$point = new Point;
$point->user_id = $userCustomer->id;
$point->point = $userPackage->price;
$point->type = 'Оформлена подписка на пользователя: ' . $userHeadPackage->name . ' (' . $userHeadPackage->username . ')'; //YSV ENUM!
$point->direction = DirectionEnum::EXPENSE();
$point->save();
$point = new Point;
$point->user_id = $userHeadPackage->id;
$point->point = $userPackage->price;
$point->type = 'Пользователь оформил платную подписку: ' . $userCustomer->name . ' (' . $userCustomer->username . ')'; //YSV ENUM!
$point->direction = DirectionEnum::COMING();
$point->save();
$message = [
'user_id' => $userCustomer->id,
'node_id' => null,
];
$userHeadPackage->notify(new UserCustomPaidSubscription($message));
}
\DB::commit();
// dd($users_package_customers);
return 0;
// max
// $users_package_customers = DB::table('users_package_customers')
// ->select(DB::raw('max(time_end) as last_time, avg(attempt_auto_paid) as attempt_auto_paid_avg,customer_id,package_id'))
// ->groupBy('customer_id', 'package_id')
// ->havingRaw('MAX(time_end) <= ?', [now()])
// ->havingRaw('AVG(attempt_auto_paid) < ?', [3])
// ->get();
// foreach ($users_package_customers as $users_package_customer) {
// $userCustomer = User::find($users_package_customer->customer_id);
// $userPackage = UserPackage::find($users_package_customer->package_id);
// $userHeadPackage = User::find($userPackage->user_id);
// $balance = SubscriptionService::calculate($userCustomer->id);
// if ($userPackage->price > $balance) {
// DB::table('users_package_customers')
// ->where('customer_id', $users_package_customer->customer_id)
// ->where('package_id', $users_package_customer->package_id)
// ->increment('attempt_auto_paid');
// continue;
// }
// DB::table('users_package_customers')->insert([
// 'user_id' => $userHeadPackage->id,
// 'customer_id' => $userCustomer->id,
// 'package_id' => $userPackage->id,
// 'price' => $userPackage->price,
// // 'time_end' => now()->addMonths(),
// 'time_end' => now()->addMinutes(10),
// 'created_at' => now(),
// ]);
// $point = new Point;
// $point->user_id = $userCustomer->id;
// $point->point = $userPackage->price;
// $point->type = 'Оформлена подписка на пользователя: ' . $userHeadPackage->username; //YSV ENUM!
// $point->direction = DirectionEnum::EXPENSE();
// $point->save();
// $point = new Point;
// $point->user_id = $userHeadPackage->id;
// $point->point = $userPackage->price;
// $point->type = 'Пользователь оформил платную подписку: ' . $userCustomer->username; //YSV ENUM!
// $point->direction = DirectionEnum::COMING();
// $point->save();
// $message = [
// 'user_id' => $userCustomer->id,
// 'node_id' => null,
// ];
// $userHeadPackage->notify(new UserCustomPaidSubscription($message));
// }
// return 0;
}
}

43
app/Console/Kernel.php Executable file
View File

@@ -0,0 +1,43 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('teaser:user-auto-subs')->weekly();
$schedule->command('teaser:auto-subs-app')->weekly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Domain\Comments\Models;
use App\Models\User;
use App\Models\Model;
use App\Domain\Feeds\Models\Feed;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Domain\Complaints\Models\CommentComplaint;
class Comment extends Model
{
use SoftDeletes;
public function feed()
{
return $this->belongsTo(Feed::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function answer_to()
{
return $this->belongsTo(User::class, 'to_user_id');
}
public function parent()
{
return $this->belongsTo(Comment::class, 'parent_id');
}
public function children()
{
return $this->hasMany(Comment::class, 'parent_id');
}
public function complaints()
{
return $this->hasMany(CommentComplaint::class);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Domain\Comments\Observers;
use App\Domain\Comments\Models\Comment;
class NovaCommentObserver
{
public function deleting(Comment $comment)
{
if(!$comment->trashed()){
$complaints = $comment->complaints;
foreach ($complaints as $complaint) {
$complaint->status = 'reviewed_bad';
$complaint->moderator_checking_id = auth()->id();
$complaint->save();
}
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Domain\Complaints\Models;
use App\Models\User;
use App\Models\Model;
use App\Domain\Comments\Models\Comment;
use App\Domain\Complaints\Models\Reason;
class CommentComplaint extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function moderator()
{
return $this->belongsTo(User::class, 'moderator_checking_id');
}
public function reason()
{
return $this->belongsTo(Reason::class);
}
public function comment()
{
return $this->belongsTo(Comment::class);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Domain\Complaints\Models;
use App\Domain\Feeds\Models\Feed;
use App\Models\Model;
use App\Models\User;
class Complaint extends Model
{
public static function boot()
{
parent::boot();
}
public function user()
{
return $this->belongsTo(User::class);
}
public function moderator()
{
return $this->belongsTo(User::class, 'moderator_checking_id');
}
public function reason()
{
return $this->belongsTo(Reason::class);
}
public function feed()
{
return $this->belongsTo(Feed::class);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Domain\Complaints\Models;
use App\Models\Model;
class Reason extends Model
{
public $timestamps = false;
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Domain\Complaints\Observers;
use App\Domain\Complaints\Models\Complaint;
class ComplaintObserver
{
public function updating(Complaint $complaint)
{
if (empty($complaint->moderator_checking_id)) {
$complaint->moderator_checking_id = auth()->user()->id;
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Domain\Feeds\Action;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Tags\Action\CreateTagAction;
class CreateFeedAction
{
public $tooFeedAction;
public $tagAction;
public function __construct(ToFeedAction $tooFeedAction, CreateTagAction $tagAction)
{
$this->tooFeedAction = $tooFeedAction;
$this->tagAction = $tagAction;
}
public function __invoke($dataFeed)
{
$feed = ($this->tooFeedAction)($dataFeed);
if(count($dataFeed->tags)){
$idsTag = ($this->tagAction)($dataFeed->tags);
$feed->tags()->sync($idsTag);
}
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace App\Domain\Feeds\DataTransferObjects;
use App\Domain\Feeds\Enums\CollectionMediaEnum;
use App\Domain\Feeds\Service\FeedMediaTransform;
use Spatie\DataTransferObject\DataTransferObject;
class FeedData extends DataTransferObject
{
public static function fromAds($feed)
{
$user = new \stdClass();
$user->id = 999999;
$user->name = 'Реклама';
$user->username = 'Реклама';
$user->color = '#795541';
$user->user_char = 'AD';
return [
'id' => $feed->id,
'type' => $feed->type,
'user' => (array)$user,
'entity' => self::fromDataAds($feed, CollectionMediaEnum::COMMON()),
];
}
public static function fromDataAds($feed, $collection_media_name)
{
$entity = (object) [];
$entity->title = $feed->title;
$entity->body = nl2br($feed->body);
$entity->views_count = $feed->views_count;
$entity->slug = $feed->slug;
$entity->type = $feed->type;
$entity->created_at_humans = $feed->created_at->diffForHumans();
$mediaTransform = (new FeedMediaTransform($feed))
->addCollectionMediaName($collection_media_name)
->spot();
$entity->preview = $mediaTransform['preview'];
$entity->collection_medias = $mediaTransform['medias'];
$entity->is_ads = true;
$entity->is_repost = false;
$entity->price = null;
$entity->is_paid = 0;
$entity->likes = 0;
$entity->liked = false;
$entity->tags = [];
$entity->status = 1;
$entity->comments = 0;
return $entity;
}
public static function fromDataBaseWithUser($feed, $purchased_subscriptions_by_users = [])
{
$feed_is_restrict = false;
$feed_is_restrict_name = '';
$feed_user_id = $feed->user_id;
$is_my_feed = false;
if(auth()->user()){
$is_my_feed = auth()->user()->id === $feed_user_id;
}
$feed_is_semi_paid = $feed->is_paid === 2;
// $is_adult_feed = false;
// $is_my_settings_adult_restrict = auth()->user()->allow_adult_content;
$restrict_feed_adult = false;
// if(($is_my_settings_adult_restrict === false && $is_adult_feed) && $is_my_feed === false){
// $feed_is_restrict_name = 'adults';
// $restrict_feed_adult = true;
// }
$private_user_feed = $feed->user->private;
$restrict_feed_private_account = false;
if(($feed_is_semi_paid && $private_user_feed && !in_array($feed_user_id, $purchased_subscriptions_by_users)) && $is_my_feed === false){
$feed_is_restrict_name = 'prohibited';
$restrict_feed_private_account = true;
}
if($restrict_feed_adult || $restrict_feed_private_account){
$feed_is_restrict = true;
}
$user = $feed->user->only('id', 'name', 'username', 'photo_path', 'color', 'user_char', 'private');
return [
'id' => $feed->id,
'type' => $feed_is_restrict ? $feed_is_restrict_name : $feed->type,
'user' => $user,
'entity' => $feed_is_restrict ? null : self::fromData($feed, CollectionMediaEnum::COMMON()),
];
}
public static function fromData($feed, $collection_media_name)
{
$entity = (object) [];
$entity->title = $feed->title;
$entity->body = $feed->body;
$entity->views_count = $feed->views_count;
$entity->price = $feed->price;
$entity->is_paid = $feed->is_paid;
$entity->is_ads = false;
// $entity->is_adult = $feed->is_adult;
$entity->slug = $feed->slug;
$entity->type = $feed->type;
$entity->is_repost = $feed->is_repost;
$entity->likes = $feed->likes_count;
$entity->liked = $feed->liked ?? false;
$entity->tags = $feed->tags;
$entity->status = $feed->status;
$entity->comments = $feed->comments_count;
$entity->created_at_humans = $feed->created_at->diffForHumans();
$mediaTransform = (new FeedMediaTransform($feed))
->addCollectionMediaName($collection_media_name)
->spot();
$entity->preview = $mediaTransform['preview'];
$entity->collection_medias = $mediaTransform['medias'];
return $entity;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Domain\Feeds\DataTransferObjects;
use Spatie\DataTransferObject\DataTransferObjectCollection;
class FeedDataCollection extends DataTransferObjectCollection
{
public static function create(array $data)
{
return new static(FeedData::arrayOf($data));
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Domain\Feeds\Enums;
use Spatie\Enum\Laravel\Enum;
/**
* @method static self PREVIEW()
* @method static self PAID()
* @method static self COMMON()
*/
final class CollectionMediaEnum extends Enum
{
protected static function values(): array
{
return [
'PREVIEW' => 'preview',
'PAID' => 'paid',
'COMMON' => 'common',
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Domain\Feeds\Enums;
use Spatie\Enum\Laravel\Enum;
/**
* @method static self PENDING()
* @method static self APPROVED()
* @method static self BANNED()
* @method static self EDITABLE()
*/
final class StatusEnum extends Enum
{
protected static function values(): array
{
return [
'PENDING' => 0,
'APPROVED' => 1,
'BANNED' => 2,
'EDITABLE' => 3,
];
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace App\Domain\Feeds\Models;
use App\Models\User;
use App\Models\Model;
use App\Domain\Tags\Models\Tag;
use Spatie\MediaLibrary\HasMedia;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Domain\Comments\Models\Comment;
use App\Domain\Complaints\Models\Complaint;
use Spatie\MediaLibrary\InteractsWithMedia;
use App\Domain\Feeds\Observers\FeedObserver;
use Illuminate\Database\Eloquent\SoftDeletes;
class Feed extends Model implements HasMedia
{
use InteractsWithMedia, SoftDeletes;
public function getUserTypeAttribute()
{
return $this->user->type;
}
protected $casts = [
'is_paid' => 'integer',
'is_ads' => 'boolean',
'status' => StatusEnum::class,
];
protected static function boot()
{
parent::boot();
self::observe(FeedObserver::class);
}
public function feedable()
{
return $this->morphTo();
}
public function tags()
{
return $this->belongsToMany(Tag::class, 'feed_tags');
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function views()
{
return $this->belongsToMany(User::class, 'users_feeds_view');
}
public function likes()
{
return $this->belongsToMany(User::class, 'users_feeds_like');
}
public function user()
{
return $this->belongsTo(User::class);
}
public function who_boughts()
{
return $this->belongsToMany(User::class, 'user_feed_purchase')->withPivot('amount')->withTimestamps();
}
public function complaints()
{
return $this->hasMany(Complaint::class);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Domain\Feeds\Observers;
use Illuminate\Support\Str;
use App\Domain\Feeds\Models\Feed;
use App\Events\FeedAddProcessed;
use App\Events\FeedRemoveProcessed;
use App\Events\FeedUpdateProcessed;
class FeedObserver
{
public function creating(Feed $feed)
{
$uuid = (string) Str::uuid();
$feed->slug = $uuid . '_' . $feed->type;
}
public function created(Feed $feed)
{
FeedAddProcessed::dispatch($feed);
}
public function deleted(Feed $feed)
{
FeedRemoveProcessed::dispatch($feed);
}
// public function forceDeleted(Feed $feed)
// {
// dd('forceDeleted');
// }
public function updated(Feed $feed)
{
FeedUpdateProcessed::dispatch($feed);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Domain\Feeds\Observers;
use App\Models\User;
use App\Domain\Feeds\Models\Feed;
class NovaFeedAdsObserver
{
public function creating(Feed $feed){
if(str_contains( request()->getPathInfo(), '/nova-api/feed-ads')){
$user = User::system();
$feed->user_id = $user->id;
$feed->is_ads = true;
$feed->created_at = now();
$feed->updated_at = now();
}
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Domain\Feeds\Observers;
use App\Domain\Feeds\Models\Feed;
use App\Notifications\RemoveFeed;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Notifications\BannedMessageFeed;
class NovaFeedObserver
{
public function updating(Feed $feed)
{
$oldStatus = $feed->getOriginal('status');
$newStatus = $feed->status;
if(($oldStatus === StatusEnum::PENDING() || $oldStatus === StatusEnum::EDITABLE()) && $newStatus === StatusEnum::BANNED()){
$user = $feed->user;
$message = [
'user_id' => $user->id,
'node_id' => $feed->id,
'text' => $feed->status_note,
'success' => false
];
$user->notify(new BannedMessageFeed($message));
}
if(($oldStatus === StatusEnum::PENDING() || $oldStatus === StatusEnum::EDITABLE()) && $newStatus === StatusEnum::APPROVED()){
$user = $feed->user;
$message = [
'user_id' => $user->id,
'node_id' => $feed->id,
'text' => $feed->status_note,
'success' => true
];
$user->notify(new BannedMessageFeed($message));
$feed->status_note = '';
}
}
public function deleting(Feed $feed)
{
if(!$feed->trashed()){
$complaints = $feed->complaints;
foreach ($complaints as $complaint) {
$complaint->status = 'reviewed_bad';
$complaint->moderator_checking_id = auth()->id();
$complaint->save();
}
$user = $feed->user;
$message = [
'user_id' => $user->id,
'node_id' => $feed->id,
];
$user->notify(new RemoveFeed($message));
}
}
}

View File

@@ -0,0 +1,262 @@
<?php
namespace App\Domain\Feeds\Queries;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\Enums\StatusEnum;
use Illuminate\Database\Eloquent\Builder;
use App\Domain\Feeds\DataTransferObjects\FeedData;
use App\Domain\Subscriptions\Service\SubscriptionService;
class FeedQueryBuilder
{
const PAGINATION_COUNT = 10;
public $feed;
public $pagination = true;
public $onlyActiveFeed = true;
public $nextCursor;
public $is_ads = false;
public $hasPages;
public function __construct($query = null)
{
if($query){
$this->feed = $query;
}else{
$this->feed = Feed::query();
}
}
public function enableAdvertising()
{
$this->is_ads = true;
return $this;
}
public function search($filters)
{
$this->feed->when($filters['search'] ?? null, function ($query, $search) {
$query->where(function ($query) use ($search) {
$query->where('title', 'ilike', '%'.$search.'%')
->orWhere('body', 'ilike', '%'.$search.'%');
});
});
return $this;
}
public function addTags($tags)
{
$this->feed->whereHas('tags', function (Builder $query) use($tags) {
$query->whereIn('id', $tags);
});
return $this;
}
public function addType($type)
{
if($type == 'image'){
//$this->feed->whereHasMorph('feedable', [Image::class]);
$this->feed->where('type', 'images');
}
if($type == 'video'){
// $this->feed->whereHasMorph('feedable', [Video::class]);
$this->feed->where('type', 'videos');
}
if($type == 'music'){
//$this->feed->whereHasMorph('feedable', [Music::class]);
$this->feed->where('type', 'musics');
}
return $this;
}
public function filter($filter = null)
{
if($filter === 'hot'){
return $this->order('likes_count');
}
return $this->order();
}
public function order($by = null)
{
if($by){
$this->feed->orderBy($by, 'desc');
}else{
$this->feed->orderBy('id', 'desc');
}
return $this;
}
public function selectBy($where, $by)
{
$this->feed->where($where, $by);
return $this;
}
public function selectByIds($ids)
{
if(is_array($ids)){
$this->feed->whereIn('id', $ids);
}else{
$this->feed->where('id', $ids);
}
return $this;
}
public function withTrashed() {
$this->feed->withTrashed();
return $this;
}
public function disableActiveFeed()
{
$this->onlyActiveFeed = false;
return $this;
}
public function disablePaginate()
{
$this->pagination = false;
return $this;
}
public function getData()
{
if($this->onlyActiveFeed){
$this->feed = $this->feed->where('status', StatusEnum::APPROVED());
}
$this->feed = $this->feed->withCount([
'comments',
'likes',
]);
if(auth()->user()){
$this->feed = $this->feed
->withCount(['likes as liked' => function (Builder $query) {
$query->where('user_id', auth()->user()->id);
}])
->withCasts(['liked' => 'boolean']);
}
if($this->pagination){
$this->feed = $this->feed->cursorPaginate(self::PAGINATION_COUNT);
$this->getCursorHash();
}else{
$this->feed = $this->feed->get();
}
return $this;
}
protected function getCursorHash()
{
$this->hasPages = $this->feed->hasMorePages();
$this->nextCursor = get_cursor_hash($this->feed);
}
public function withTags()
{
$this->feed->with('tags:id,name,slug');
return $this;
}
public function withUser()
{
$this->feed->with('user:id,first_name,last_name,username,photo_path,color,user_char,private');
return $this;
}
public function withFeedable()
{
// $this->feed->with('media');
// :id,model_type,model_id,name,file_name,collection_name,custom_properties
if(auth()->user()){
$this->feed->withCount('media')
->with(['media' => function($query){
// withCount('likes')->withCasts(['likes_count' => 'boolean']);
$query->withCount(['likes' => function (Builder $query) {
$query->where('user_id', auth()->user()->id);
}])->withCasts(['likes_count' => 'boolean']);
}]);
}else{
$this->feed->with('media');
}
return $this;
// $this->feed->with('feedable', function (MorphTo $morphTo) {
// $morphTo->morphWith([
// Image::class => ['media'],
// Video::class => ['media'],
// Music::class => ['media'],
// ]);
// });
// return $this;
}
public function transformData()
{
$feed_collect = collect();
if(auth()->user()){
$purchased_subscriptions_by_users = \DB::table('users_package_customers')
->where('customer_id', auth()->user()->id)
->where('time_end', '>', now())
->pluck('user_id')->toArray();
}else{
$purchased_subscriptions_by_users = [];
}
foreach ($this->feed as $feed) {
$feed = FeedData::fromDataBaseWithUser($feed, $purchased_subscriptions_by_users);
if($feed['entity']){
$feed['entity']->tags->transform(function ($item) {
return [
'id' => $item->id,
'name' => $item->name,
'slug' => $item->slug,
];
});
}
$feed_collect[] = $feed;
}
if(auth()->check()){
$subscription_purchased = SubscriptionService::activeSubscription();
if($subscription_purchased == false){
$adsMedia = Feed::where('is_ads', true)->with('media')->inRandomOrder()->first();
if($adsMedia && $this->is_ads){
$adsMediaData = FeedData::fromAds($adsMedia);
$feed_collect->splice(4, 0, [$adsMediaData]);
}
}
}
return $feed_collect;
}
public function build()
{
$this
->withFeedable()
->withUser()
->withTags()
->getData();
return $this;
}
public function transformGet()
{
return $this
->withFeedable()
->withUser()
->withTags()
->getData()->transformData();
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace App\Domain\Feeds\Service;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\Enums\CollectionMediaEnum;
class FeedMediaTransform
{
public $feed;
public $type;
public $typeUrl = 'web';
public $collection_name;
public function __construct(Feed $feed)
{
$this->feed = $feed;
$this->type = $feed->type;
}
public function getFullPath()
{
$this->typeUrl = 'disk';
return $this;
}
public function paid()
{
return $this->addCollectionMediaName(CollectionMediaEnum::PAID());
}
public function default()
{
return $this->addCollectionMediaName(CollectionMediaEnum::COMMON());
}
public function addCollectionMediaName($collection_name)
{
$this->collection_name = $collection_name;
return $this;
}
public function spot()
{
if($this->type === 'images'){
return $this->images();
}
if($this->type === 'videos'){
return $this->videos();
}
if($this->type === 'musics'){
return $this->musics();
}
}
public function videos()
{
$collection = [];
$medias = $this->feed->getMedia($this->collection_name);
$medias->each(function ($item) use (&$collection) {
$collection[] = [
'url' => $this->typeUrl === 'web' ? $item->getFullUrl() : $item->getPath(),
'id' => $item->id,
];
});
return [
'preview' => $this->getPreview(),
'medias' => $collection,
];
}
public function images()
{
$collection = [];
$medias = $this->feed->getMedia($this->collection_name);
$medias->each(function ($item) use (&$collection) {
$collection[] = [
'url' => $this->typeUrl === 'web' ? $item->getFullUrl() : $item->getPath(),
'id' => $item->id,
];
});
return [
'preview' => $this->getPreview(),
'medias' => $collection,
];
}
public function musics()
{
$collection = [];
$medias = $this->feed->getMedia($this->collection_name);
$medias->each(function ($item) use (&$collection) {
$collection[] = [
'url' => $this->typeUrl === 'web' ? $item->getFullUrl() : $item->getPath(),
'name' => $item->name,
'playing' => false,
'liked' => $item->likes_count ?? false,
'time' => $item->getCustomProperty('time'),
'id' => $item->id,
];
});
return [
'preview' => $this->getPreview(),
'medias' => $collection,
];
}
public function getPreview($type = 0)
{
if($this->type === 'images'){
$img_preview = $this->feed->getMedia($this->collection_name)->first();
if($img_preview){
if($type){
return $img_preview;
}
return $img_preview->getFullUrl();
}
}
$preview = $this->feed->getMedia(CollectionMediaEnum::PREVIEW());
if($type){
return $preview->count() ? $preview->first() : null;
}
return $preview->count() ? $preview->first()->getFullUrl() : null;
}
public function getPreviewObject()
{
$preview = $this->getPreview(1);
if($preview){
return [ 'id'=> $preview->id, 'url' => $preview->getFullUrl() ];
}
return null;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Domain\Feeds\Service;
use DB;
class LiveFeed
{
public static function addBySub($user)
{
$userID = $user->id;
$userFeeds = $user->feeds()->pluck('created_at', 'id')->transform(function ($item) {
return ['times' => $item->getTimestamp()];
})->toArray();
$add_posts = [];
foreach ($userFeeds as $feedID => $userFeed) {
$add_posts[] = [
'feed_id' => $feedID,
'user_id' => auth()->user()->id,
'home_user_id' => $userID,
'times' => $userFeed['times'],
];
}
DB::table('users_live_feeds')->insertOrIgnore($add_posts);
}
public static function removeBySub($user)
{
$userID = $user->id;
DB::table('users_live_feeds')
->where('home_user_id', $userID)
->where('user_id', auth()->user()->id)
->delete();
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Domain\Feeds;
interface ToFeedAction
{
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Domain\Images\Action;
use DB;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Images\DataTransferObjects\ImageData;
class CreateImageAction implements ToFeedAction
{
public function __invoke(ImageData $imageData)
{
DB::beginTransaction();
$imageFeed = Feed::create([
'title' => $imageData->title,
'body' => $imageData->body,
'price' => $imageData->price,
'is_paid' => $imageData->is_paid,
'user_id' => $imageData->user->id,
'is_ads' => false,
'type' => 'images',
]);
foreach ($imageData->photos as $photo) {
$imageFeed->addMedia($photo)->toMediaCollection('common');
}
if($imageData->is_loaded_photos_paid){
foreach ($imageData->photos_paid as $photo) {
$imageFeed->addMedia($photo)->toMediaCollection('paid');
}
}
DB::commit();
return $imageFeed;
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Domain\Images\Action;
use DB;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Domain\Images\DataTransferObjects\ImageData;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class UpdateImageAction implements ToFeedAction
{
public $imageFeed;
public function __construct(Feed $imageFeed)
{
$this->imageFeed = $imageFeed;
}
public function __invoke(ImageData $imageData)
{
$status = $this->imageFeed->status;
if($status === StatusEnum::BANNED()){
$status = StatusEnum::EDITABLE();
}
if($status === StatusEnum::APPROVED()){
$status = StatusEnum::EDITABLE();
}
DB::beginTransaction();
$this->imageFeed->fill([
'title' => $imageData->title,
'body' => $imageData->body,
'price' => $imageData->price,
'is_paid' => $imageData->is_paid,
'status' => $status,
'is_ads' => false,
])->save();
if($imageData->is_loaded_photos){
foreach ($imageData->photos as $photo) {
$this->imageFeed->addMedia($photo)->toMediaCollection('common');
}
}
if($imageData->is_loaded_photos_paid){
foreach ($imageData->photos_paid as $photo) {
$this->imageFeed->addMedia($photo)->toMediaCollection('paid');
}
}
if(count($imageData->removedItems)){
foreach ($imageData->removedItems as $removedItem) {
if($media = Media::find($removedItem)){
$media->delete();
}
}
}
DB::commit();
return $this->imageFeed->refresh();
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Domain\Images\DataTransferObjects;
use App\Http\Requests\ImageFormRequest;
use Spatie\DataTransferObject\DataTransferObject;
class ImageData extends DataTransferObject
{
public $title;
public $body;
public $user;
public $photos;
public $price;
public $tags;
public $is_paid;
public $is_loaded_photos_paid;
public $is_loaded_photos;
public $photos_paid;
public $removedItems;
public static function fromRequest(ImageFormRequest $request)
{
return new self([
'title' => $request->input('title'),
'body' => $request->input('body'),
'price' => $request->input('price'),
'is_paid' => $request->input('is_paid'),
'user' => auth()->user(),
'tags' => $request->input('tags') ?? [],
'photos' => $request->file('photos'),
'is_loaded_photos' => $request->hasFile('photos'),
'photos_paid' => $request->file('photos_paid'),
'is_loaded_photos_paid' => $request->hasFile('photos_paid'),
'removedItems' => $request->input('removedItems') ?? [],
]);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Domain\Images\Models;
use App\Domain\Complaints\Models\Complaint;
use App\Domain\Feeds\Models\Feed;
use App\Models\Model;
use App\Models\User;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Image extends Model implements HasMedia
{
use InteractsWithMedia;
public function feed()
{
return $this->morphOne(Feed::class, 'feedable');
}
public function complaints()
{
return $this->morphMany(Complaint::class, 'complaintable');
}
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Domain\Medias\Models;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class TeaserMedia extends Media
{
protected $table = 'media';
public function likes()
{
return $this->belongsToMany(\App\Models\User::class, 'user_audio_like', 'media_id', 'user_id');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Domain\Messenger\Models;
use App\Models\User;
use App\Models\Model;
class ChatRoom extends Model
{
public function messsages()
{
return $this->hasMany(Message::class)->orderBy('created_at', 'desc');
}
public function latestMessage()
{
return $this->hasOne(Message::class)->latestOfMany();
}
public function users()
{
return $this->belongsToMany(User::class, 'user_chat_room');
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Domain\Messenger\Models;
use App\Models\User;
use App\Models\Model;
use App\Domain\Messenger\Models\ChatRoom;
class Message extends Model
{
// protected $touches = ['room'];
public function user()
{
return $this->belongsTo(User::class);
}
public function room()
{
return $this->belongsTo(ChatRoom::class, 'chat_room_id');
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace App\Domain\Musics\Action;
use DB;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Musics\DataTransferObjects\MusicData;
class CreateMusicAction implements ToFeedAction
{
public function __invoke(MusicData $musicData)
{
DB::beginTransaction();
if(empty($musicData->title)){
$file_count = count($musicData->musics);
$first_file = $musicData->musics[0]->getClientOriginalName();
$filename = pathinfo($first_file, PATHINFO_FILENAME);
$musicData->title = $filename . ' (' . $file_count . ')';
}
$musicFeed = Feed::create([
'title' => $musicData->title,
'body' => $musicData->body,
'price' => $musicData->price,
'is_paid' => $musicData->is_paid,
'user_id' => $musicData->user->id,
'is_ads' => false,
'type' => 'musics',
]);
$result_time_common = $this->calcTimeFile($musicData->times);
foreach ($musicData->musics as $music) {
$name = $music->getClientOriginalName();
$time = @$result_time_common[$name];
$musicFeed->addMedia($music)
->withCustomProperties(['time' => $time])
->toMediaCollection('common');
}
if($musicData->is_loaded_preview){
$musicFeed->addMedia($musicData->preview)->toMediaCollection('preview');
}
if($musicData->is_loaded_paid_music){
$result_time_paids = $this->calcTimeFile($musicData->times_paid);
foreach ($musicData->musics_paid as $music) {
$name = $music->getClientOriginalName();
$time = @$result_time_paids[$name];
$musicFeed->addMedia($music)
->withCustomProperties(['time' => $time])
->toMediaCollection('paid');
}
}
DB::commit();
return $musicFeed;
}
protected function calcTimeFile($time_musics)
{
$times = array_map(function($line){
$line = explode(',', $line);
return [$line[0] => $line[1]];
}, $time_musics);
return array_merge(...$times);
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace App\Domain\Musics\Action;
use DB;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Domain\Musics\DataTransferObjects\MusicData;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class UpdateMusicAction implements ToFeedAction
{
public $musicFeed;
public function __construct(Feed $musicFeed)
{
$this->musicFeed = $musicFeed;
}
public function __invoke(MusicData $musicData)
{
$status = $this->musicFeed->status;
if($status === StatusEnum::BANNED()){
$status = StatusEnum::EDITABLE();
}
if($status === StatusEnum::APPROVED()){
$status = StatusEnum::EDITABLE();
}
DB::beginTransaction();
$this->musicFeed->fill([
'title' => $musicData->title,
'body' => $musicData->body,
'price' => $musicData->price,
'is_paid' => $musicData->is_paid,
'is_ads' => false,
'status' => $status,
])->save();
if($musicData->is_loaded_preview){
if($existPreview = $this->musicFeed->getMedia('preview')->first()){
$existPreview->delete();
}
$this->musicFeed->addMedia($musicData->preview)->toMediaCollection('preview');
}
if($musicData->is_loaded_music){
$result_time_common = $this->calcTimeFile($musicData->times);
foreach ($musicData->musics as $music) {
$name = $music->getClientOriginalName();
$time = @$result_time_common[$name];
$this->musicFeed->addMedia($music)
->withCustomProperties(['time' => $time])
->toMediaCollection('common');
}
}
if($musicData->is_loaded_paid_music){
$result_time_paids = $this->calcTimeFile($musicData->times_paid);
foreach ($musicData->musics_paid as $music) {
$name = $music->getClientOriginalName();
$time = @$result_time_paids[$name];
$this->musicFeed->addMedia($music)
->withCustomProperties(['time' => $time])
->toMediaCollection('paid');
}
}
if(count($musicData->removedItems)){
foreach ($musicData->removedItems as $removedItem) {
if($media = Media::find($removedItem)){
$media->delete();
}
}
}
DB::commit();
return $this->musicFeed->refresh();
}
protected function calcTimeFile($time_musics)
{
$times = array_map(function($line){
$line = explode(',', $line);
return [$line[0] => $line[1]];
}, $time_musics);
return array_merge(...$times);
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Domain\Musics\DataTransferObjects;
use App\Http\Requests\MusicFormRequest;
use Spatie\DataTransferObject\DataTransferObject;
class MusicData extends DataTransferObject
{
public $title;
public $body;
public $user;
public $musics;
public $musics_paid;
public $preview;
public $is_loaded_music;
public $is_loaded_paid_music;
public $is_loaded_preview;
public $price;
public $times;
public $times_paid;
public $is_paid;
public $tags;
public $removedItems;
public static function fromRequest(MusicFormRequest $request)
{
return new self([
'title' => $request->input('title'),
'body' => $request->input('body'),
'price' => $request->input('price'),
'is_paid' => $request->input('is_paid'),
'user' => auth()->user(),
'tags' => $request->input('tags') ?? [],
'preview' => $request->file('preview'),
'is_loaded_preview' => $request->hasFile('preview'),
'musics' => $request->file('musics'),
'is_loaded_music' => $request->hasFile('musics'),
'musics_paid' => $request->file('musics_paid'),
'is_loaded_paid_music' => $request->hasFile('musics_paid'),
'times' => $request->input('times'),
'times_paid' => $request->input('times_paid'),
'removedItems' => $request->input('removedItems') ?? [],
]);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Domain\Musics\Models;
use App\Domain\Complaints\Models\Complaint;
use App\Domain\Feeds\Models\Feed;
use App\Models\Model;
use App\Models\User;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Music extends Model implements HasMedia
{
use InteractsWithMedia;
protected $table = 'musics';
public function complaints()
{
return $this->morphMany(Complaint::class, 'complaintable');
}
public function feed()
{
return $this->morphOne(Feed::class, 'feedable');
}
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace App\Domain\PaymentGateway\Models;
use App\Models\User;
use App\Models\Model;
use Illuminate\Support\Str;
class PaymentGatewayOrder extends Model
{
const TYPE_INTERKASSA_NAME = "interkassa";
const TYPE_UNITPAY_NAME = "unitpay";
const TYPE_QIWI_NAME = "qiwi";
const TYPE_YOO_NAME = "yookassa";
public function user()
{
return $this->belongsTo(User::class);
}
public static function interkassa($amount)
{
$paymentGatewayOrder = new PaymentGatewayOrder;
$paymentGatewayOrder->user_id = auth()->user()->id;
$paymentGatewayOrder->amount = $amount;
$paymentGatewayOrder->status = 0; // 0 - created/ 1- success/ 2-error/ 3-pending
$paymentGatewayOrder->type = self::TYPE_INTERKASSA_NAME;
$paymentGatewayOrder->save();
return $paymentGatewayOrder;
}
public static function unitpay($amount)
{
$paymentGatewayOrder = new PaymentGatewayOrder;
$paymentGatewayOrder->user_id = auth()->user()->id;
$paymentGatewayOrder->amount = $amount;
$paymentGatewayOrder->status = 0; // 0 - created/ 1- success/ 2-error/ 3-pending
$paymentGatewayOrder->type = self::TYPE_UNITPAY_NAME;
$paymentGatewayOrder->save();
return $paymentGatewayOrder;
}
public static function qiwi($amount)
{
$paymentGatewayOrder = new PaymentGatewayOrder;
$paymentGatewayOrder->user_id = auth()->user()->id;
$paymentGatewayOrder->amount = $amount;
$paymentGatewayOrder->number = (string) Str::uuid();
$paymentGatewayOrder->status = 0; // 0 - created/ 1- success/ 2-error/ 3-pending
$paymentGatewayOrder->type = self::TYPE_QIWI_NAME;
$paymentGatewayOrder->save();
return $paymentGatewayOrder;
}
public static function yookassa($amount)
{
$paymentGatewayOrder = new PaymentGatewayOrder;
$paymentGatewayOrder->user_id = auth()->user()->id;
$paymentGatewayOrder->amount = $amount;
$paymentGatewayOrder->number = (string) Str::uuid();
$paymentGatewayOrder->status = 0; // 0 - created/ 1- success/ 2-error/ 3-pending
$paymentGatewayOrder->type = self::TYPE_YOO_NAME;
$paymentGatewayOrder->save();
return $paymentGatewayOrder;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Domain\PaymentGateway\Services;
class InterkassaService
{
public static function payments_link($amount, $order_id)
{
$configuration = new \Interkassa\Helper\Config();
$configuration->setCheckoutSecretKey(env('INTERKASSA_SECRET_KEY'));
$configuration->setAuthorizationKey(env('INTERKASSA_AUTH_KEY'));
$configuration->setAccountId(env('INTERKASSA_ACCOUNT_ID'));
$SDKClient = new \Interkassa\Interkassa($configuration);
$invoiceRequest = new \Interkassa\Request\GetInvoiceRequest();
$invoiceRequest
->setCheckoutId(env('INTERKASSA_ID'))
->setPaymentNumber($order_id)
->setAmount($amount)
->setCurrency('RUB')
->setDescription('Пополнение баланса');
return $SDKClient->makeInvoiceSciLink($invoiceRequest);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Domain\PaymentGateway\Services;
class QiwiService
{
public static function payments_link($amount, $order, $user)
{
$publicKey = env('QIWI_PUBLIC');
$SECRET_KEY = env('QIWI_SECRET');
$billPayments = new \Qiwi\Api\BillPayments($SECRET_KEY);
$success_url = env('APP_URL') . '/qiwi-to-payments/status/' . $order->number;
$params = [
'publicKey' => $publicKey,
'amount' => $amount,
'billId' => $order->number,
'successUrl' => $success_url,
'email' => $user->email,
'comment' => 'Пополнение баланса',
];
return $billPayments->createPaymentForm($params);
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Domain\PaymentGateway\Services;
use UnitPay;
use CashItem;
class UnitpayService
{
public static function payments_link($amount, $order_id)
{
// Project Data
$domain = 'unitpay.ru';// Your working domain: unitpay.ru or address provided by unitpay support service
$secretKey = '72449d551500fb99bb66499203ed1ccb';// Project secret key
$publicId = 'demo';
// $publicId = '438925-9eafe';
// My item Info
$itemName = 'Пополнение баланса';
// My Order Data
$orderId = $order_id;
$orderSum = $amount;
$orderDesc = 'Payment for item "' . $itemName . '"';
$orderCurrency = 'RUB';
$unitpay = new UnitPay($domain, $secretKey);
// ->setCustomerEmail('customer@domain.com')
// ->setCustomerPhone('79001235555')
$unitpay
->setBackUrl('https://teeaseer.com')
->setCashItems([
new CashItem($itemName, 1, $orderSum)
]);
$redirectUrl = $unitpay->form(
$publicId,
$orderSum,
$orderId,
$orderDesc,
$orderCurrency
);
return $redirectUrl;
// $configuration = new \Interkassa\Helper\Config();
// $configuration->setCheckoutSecretKey(env('INTERKASSA_SECRET_KEY'));
// $configuration->setAuthorizationKey(env('INTERKASSA_AUTH_KEY'));
// $configuration->setAccountId(env('INTERKASSA_ACCOUNT_ID'));
// $SDKClient = new \Interkassa\Interkassa($configuration);
// $invoiceRequest = new \Interkassa\Request\GetInvoiceRequest();
// $invoiceRequest
// ->setCheckoutId(env('INTERKASSA_ID'))
// ->setPaymentNumber($order_id)
// ->setAmount($amount)
// ->setCurrency('RUB')
// ->setDescription('Пополнение баланса');
// return $SDKClient->makeInvoiceSciLink($invoiceRequest);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Domain\PaymentGateway\Services;
use YooKassa\Client;
class YookassaService
{
public static function payments_link($amount, $order, $user)
{
$YOOKASSA_SHOP_ID = env('YOOKASSA_SHOP_ID');
$YOOKASSA_KEY = env('YOOKASSA_KEY');
$idempotenceKey = $order->number;
$client = new Client();
$client->setAuth($YOOKASSA_SHOP_ID, $YOOKASSA_KEY);
$success_url = env('APP_URL') . '/payments/status/' . $order->number;
$response = $client->createPayment(
[
'amount' => [
'value' => $amount,
'currency' => 'RUB',
],
'capture' => true,
'payment_method_data' => [
'type' => 'sbp',
],
'confirmation' => [
'type' => 'redirect',
'return_url' => $success_url,
],
'receipt' => [
'customer' => [
'full_name' => $user->name ?? $user->username,
'phone' => $user->phone,
"email" => $user->email
],
'items' => [
[
'description' => 'оплата бонусов тизер',
'quantity' => 1.00,
'amount' => [
'value' => $amount,
'currency' => 'RUB',
],
'vat_code' => 1,
'payment_mode' => 'full_payment'
]
]
],
'description' => 'Заказ №' . $order->id,
],
$idempotenceKey
);
$order->system_payment_id = $response->getId();
$order->save();
$confirmationUrl = $response->getConfirmation()->getConfirmationUrl();
return $confirmationUrl;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Domain\Payments\Models;
use App\Models\Model;
use App\Models\User;
class BankRequisites extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function requisites()
{
return $this->morphOne(Requisites::class, 'requisiteable');
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Domain\Payments\Models;
use App\Models\Model;
use App\Models\User;
class Requisites extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function requisiteable()
{
return $this->morphTo();
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Domain\Payments\Models;
use App\Models\User;
use App\Models\Model;
use App\Domain\Points\Models\Point;
class Withdrawal extends Model
{
public function getUserPhoneAttribute()
{
return $this->user->phone;
}
public function getUserTypeAttribute()
{
return $this->user->type;
}
public function getRequisitesAttribute()
{
return 'ИНН: ' . $this->user->inn . ' ' .
'БИК: ' . $this->user->bik . ' ' .
'Счет: ' . $this->user->checking_account;
}
public static function getTotalAmountForUserInCurrentMonth($userId)
{
return self::where('user_id', $userId)
->where('status', '<>', 'cancel')
->where('created_at', '>=', now()->startOfMonth())
->where('created_at', '<', now()->startOfMonth()->addMonth())
->sum('amount');
}
public static function canRequestWithdrawalPhysical($userId, $requestedAmount)
{
$totalAmount = self::getTotalAmountForUserInCurrentMonth($userId);
return ($totalAmount + $requestedAmount) <= 12000;
}
public static function canRequestWithdrawalLegal($userId, $requestedAmount)
{
$totalAmount = self::getTotalAmountForUserInCurrentMonth($userId);
return ($totalAmount + $requestedAmount) <= 150000;
}
public function user()
{
return $this->belongsTo(User::class);
}
public function requisites()
{
return $this->belongsTo(Requisites::class);
}
public function point()
{
return $this->belongsTo(Point::class);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Domain\Payments\Observers;
use App\Domain\Points\Models\Point;
use App\Domain\Payments\Models\Withdrawal;
class WithdrawalObserver
{
public function updated(Withdrawal $withdrawal)
{
$status = $withdrawal->status;
$point_id = $withdrawal->point_id;
if($status === 'cancel'){
Point::destroy($point_id);
}
if($status === 'success'){
$point = Point::find($point_id);
$point->type = "Вывод средств";
$point->save();
}
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Domain\Points\Enums;
use Spatie\Enum\Laravel\Enum;
/**
* @method static self COMING()
* @method static self EXPENSE()
* @method static self PENDING()
*/
final class DirectionEnum extends Enum
{
protected static function values(): array
{
return [
'COMING' => 0, // приход
'EXPENSE' => 1, //расход
'PENDING' => 2, //ожидание
];
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Domain\Points\Models;
use App\Models\Model;
use App\Models\User;
class Point extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Domain\Subscriptions\Models;
use App\Models\Model;
class Package extends Model
{
public $timestamps = false;
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Domain\Subscriptions\Models;
use App\Models\Model;
use App\Models\User;
class Subscription extends Model
{
protected $casts = [
'ends_at' => 'datetime',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function package()
{
return $this->belongsTo(Package::class);
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace App\Domain\Subscriptions\Service;
use Carbon\Carbon;
use App\Models\User;
use App\Domain\Points\Models\Point;
use App\Domain\Subscriptions\Models\Subscription;
class SubscriptionService
{
public static function amount()
{
$subscriptions = Subscription::where('ends_at', '>', Carbon::now())
->where('status', 'complete')->get();
return $subscriptions->sum('price');
}
public static function hasSubscription()
{
return auth()->user()->subscription()->count();
}
public static function activeSubscription()
{
$last = auth()->user()->subscription()->first();
if (empty($last)) {
return false;
}
if ($last->ends_at > Carbon::now()) {
return true;
}
return false;
}
public static function freeLeaders()
{
$leader_count = nova_get_setting('vote_leader_count');
$users = \DB::table('users_subscribers')->get();
$users = $users->groupBy('subscriber_id');
$leaders = collect();
$users = $users->map(function ($item) {
return $item->sum('leader');
})->sortDesc()->take($leader_count);
foreach ($users as $user_id => $leader) {
$lUser = User::find($user_id);
$lUser->name = $lUser->name;
$lUser->countVote = $leader;
$leaders[] = $lUser;
}
return $leaders;
}
public static function leaders()
{
$leaders = \DB::select("SELECT vote.subscriber_id as user_id, SUM(vote.leader) as vote_count FROM
(
SELECT friends.subscriber_id, friends.leader
FROM users_subscribers friends,
(
SELECT user_id,ends_at FROM subscriptions
WHERE ends_at > CURRENT_TIMESTAMP
)user_active,
(
SELECT user_id,ends_at FROM subscriptions
WHERE ends_at > CURRENT_TIMESTAMP
)user_active2
where
friends.user_id = user_active.user_id
and friends.subscriber_id = user_active2.user_id
) vote
GROUP BY vote.subscriber_id ORDER BY vote_count DESC");
return $leaders;
}
public static function calculate($user_id)
{
$balance = \DB::select("SELECT T_IN.user_id, T_IN.in-T_OUT.out as balance FROM
(SELECT user_id, sum(point) as out FROM points WHERE user_id = {$user_id} AND direction = 1 GROUP BY user_id) T_OUT,
(SELECT user_id, sum(point) as in FROM points WHERE user_id = {$user_id} AND direction = 0 GROUP BY user_id) T_IN
where T_IN.user_id = T_OUT.user_id");
$balance = @$balance[0]->balance;
if (empty($balance)) {
$points = Point::where('user_id', $user_id)->get();
$in = $points->where('direction', 0)->sum('point');
$out = $points->where('direction', 1)->sum('point');
$sum = $in-$out;
if ($sum <= 0) {
return 0;
}
return $sum;
}
return $balance;
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Domain\Tags\Action;
use Illuminate\Support\Str;
use App\Domain\Tags\Models\Tag;
class CreateTagAction
{
public function __invoke(Array $tags)
{
$tagIds = [];
$tags = array_map(function($tag){
$tag = trim(strip_tags($tag));
//$tag = mb_strtolower($tag);
//$tag = mb_ucfirst($tag);
return $tag;
}, $tags);
$tags = array_unique($tags);
foreach ($tags as $tag) {
$slug = Str::slug($tag, '-');
$tagDB = Tag::firstOrCreate(
['slug' => $slug],
['name' => $tag]
);
$tagIds[] = $tagDB->id;
}
return $tagIds;
}
protected function create()
{
}
}

16
app/Domain/Tags/Models/Tag.php Executable file
View File

@@ -0,0 +1,16 @@
<?php
namespace App\Domain\Tags\Models;
use App\Models\Model;
use App\Domain\Feeds\Models\Feed;
class Tag extends Model
{
public function feeds()
{
return $this->belongsToMany(Feed::class, 'feed_tags');
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Domain\Users\DataTransferObjects;
use App\Models\User;
use Spatie\DataTransferObject\DataTransferObject;
class UserData extends DataTransferObject
{
public $id;
public $name;
public $user_char;
public $color;
public $photo_path;
public $banner_path;
public $username;
public $private;
public $is_auth_user;
public static function fromModel(User $user)
{
$idCheck = auth()->user() ? $user->id === auth()->user()->id : false;
return new self([
'id' => $user->id,
'name' => $user->name,
'user_char' => $user->user_char,
'color' => $user->color,
'photo_path' => $user->photo_path,
'banner_path' => $user->banner_path,
'username' => $user->username,
'private' => $user->private,
'is_auth_user' => $idCheck,
]);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Domain\Users\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use App\Models\Model;
class UserPackage extends Model
{
use HasFactory;
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Domain\Users\Observers;
use App\Models\User;
use Illuminate\Support\Arr;
// use App\Domain\Points\Models\Point;
// use App\Domain\Points\Enums\DirectionEnum;
class UserObserver
{
public function creating(User $user)
{
$user->color = $this->generateColors();
if(!$user->username){
$user->username = 'id_' . uniqid();
}
}
public function created(User $user)
{
// if($user->username != 'inner_systemuser_api'){
// $point = new Point;
// $point->user_id = $user->id;
// $point->point = 100;
// $point->type = 'Тестовое пополнение'; //YSV ENUM!
// $point->direction = DirectionEnum::COMING();
// $point->save();
// }
}
public function saving(User $user)
{
$user->user_char = $this->getChar($user);
}
private function generateColors()
{
$colors = ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#4caf50', '#8bc34a', '#ffc107', '#ff9800', '#ff5722', '#795548', '#9e9e9e', '#607d8b', '#f44331', '#e91e61', '#9c27b1', '#673ab1', '#3f51b1', '#2196f1', '#03a9f1', '#00bcd1', '#009681', '#4caf51', '#8bc341', '#ffc101', '#ff9801', '#ff5721', '#795541', '#9e9e91', '#607d81'];
return Arr::random($colors);
}
private function getChar($user)
{
$fname = mb_strtoupper($user->first_name);
$lname = @$user->last_name;
if($lname){
$lname = mb_strtoupper($lname);
return mb_substr($fname, 0, 1) . mb_substr($lname, 0, 1);
}
return mb_substr($fname, 0, 1) . mb_substr($fname, 1, 1);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Domain\Users\Service;
use Illuminate\Database\Eloquent\Builder;
class ProfileDataService
{
public static function get($user)
{
$gues = auth()->user();
if($gues){
$gues = auth()->user()->id;
}else{
$gues = null;
}
$user->loadCount(['subscriber_reverse as is_sub' => function (Builder $query) use($gues) {
$query->where('user_id', $gues);
},'subscribers as is_reader' => function (Builder $query) use($gues) {
$query->where('subscriber_id', $gues);
}])->withCasts(['is_sub' => 'boolean', 'is_reader' => 'boolean']);
$is_leader = false;
if($user->is_sub && auth()->user()){
$leader = auth()->user()->subscribers()->where('subscriber_id', $user->id)->first();
if($leader){
$is_leader = (boolean)$leader->pivot->leader;
}
}
$count_feeds = $user->feeds()->count();
$count_readable = $user->subscribers()->count();
$count_subscribers = $user->subscriber_reverse()->count();
$is_auth_user = $user->id === $gues;
if($is_auth_user){
$close_account = false;
}else{
$close_account = $user->private == true && ($user->is_sub == 0 || $user->is_reader == 0);
}
$object = new \stdClass();
$object->user = $user;
$object->count_feeds = $count_feeds;
$object->count_readable = $count_readable;
$object->count_subscribers = $count_subscribers;
$object->close_account = $close_account;
$object->is_leader = $is_leader;
return $object;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Domain\Videos\Action;
use App\Domain\Feeds\Models\Feed;
use DB;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Videos\DataTransferObjects\VideoData;
class CreateVideoAction implements ToFeedAction
{
public function __invoke(VideoData $videoData)
{
DB::beginTransaction();
//$youtube_code = $videoData->youtube ? $this->getCodeYoutube($videoData->youtube) : '';
$videoFeed = Feed::create([
'title' => $videoData->title,
'body' => $videoData->body,
'price' => $videoData->price,
'is_paid' => $videoData->is_paid,
'user_id' => $videoData->user->id,
'type' => 'videos',
'is_ads' => false,
//'iframe_code' => $youtube_code,
]);
foreach ($videoData->videos as $video) {
$videoFeed->addMedia($video)->toMediaCollection('common');
}
if($videoData->is_loaded_preview){
$videoFeed->addMedia($videoData->preview)->toMediaCollection('preview');
}
if($videoData->is_loaded_videos_paid){
foreach ($videoData->videos_paid as $video) {
$videoFeed->addMedia($video)->toMediaCollection('paid');
}
}
DB::commit();
return $videoFeed;
}
private function getCodeYoutube($video)
{
$youtuberegexp = '/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/i';
preg_match($youtuberegexp, $video, $matches);
return @$matches[1];
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace App\Domain\Videos\Action;
use DB;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\ToFeedAction;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Domain\Videos\DataTransferObjects\VideoData;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class UpdateVideoAction implements ToFeedAction
{
public $videoFeed;
public function __construct(Feed $videoFeed)
{
$this->videoFeed = $videoFeed;
}
public function __invoke(VideoData $videoData)
{
$status = $this->videoFeed->status;
if($status === StatusEnum::BANNED()){
$status = StatusEnum::EDITABLE();
}
if($status === StatusEnum::APPROVED()){
$status = StatusEnum::EDITABLE();
}
DB::beginTransaction();
$this->videoFeed->fill([
'title' => $videoData->title,
'body' => $videoData->body,
'price' => $videoData->price,
'is_paid' => $videoData->is_paid,
'status' => $status,
'is_ads' => false,
])->save();
if($videoData->is_loaded_video){
foreach ($videoData->videos as $video) {
$this->videoFeed->addMedia($video)->toMediaCollection('common');
}
}
if($videoData->is_loaded_preview){
if($existPreview = $this->videoFeed->getMedia('preview')->first()){
$existPreview->delete();
}
$this->videoFeed->addMedia($videoData->preview)->toMediaCollection('preview');
}
if($videoData->is_loaded_videos_paid){
foreach ($videoData->videos_paid as $video) {
$this->videoFeed->addMedia($video)->toMediaCollection('paid');
}
}
if(count($videoData->removedItems)){
foreach ($videoData->removedItems as $removedItem) {
if($media = Media::find($removedItem)){
$media->delete();
}
}
}
DB::commit();
return $this->videoFeed->refresh();
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Domain\Videos\DataTransferObjects;
use App\Http\Requests\VideoFormRequest;
use Spatie\DataTransferObject\DataTransferObject;
class VideoData extends DataTransferObject
{
public $title;
public $body;
public $user;
public $videos;
public $videos_paid;
public $preview;
public $is_loaded_video;
public $is_loaded_preview;
public $is_loaded_videos_paid;
public $price;
public $is_paid;
public $tags;
public $removedItems;
public static function fromRequest(VideoFormRequest $request)
{
return new self([
'title' => $request->input('title'),
'body' => $request->input('body'),
'price' => $request->input('price'),
'is_paid' => $request->input('is_paid'),
'user' => auth()->user(),
'tags' => $request->input('tags') ?? [],
'preview' => $request->file('preview'),
'is_loaded_preview' => $request->hasFile('preview'),
'videos' => $request->file('videos'),
'is_loaded_video' => $request->hasFile('videos'),
'videos_paid' => $request->file('videos_paid'),
'is_loaded_videos_paid' => $request->hasFile('videos_paid'),
'removedItems' => $request->input('removedItems') ?? [],
]);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Domain\Videos\Models;
use App\Domain\Complaints\Models\Complaint;
use App\Domain\Feeds\Models\Feed;
use App\Models\Model;
use App\Models\User;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Video extends Model implements HasMedia
{
use InteractsWithMedia;
public function complaints()
{
return $this->morphMany(Complaint::class, 'complaintable');
}
public function feed()
{
return $this->morphOne(Feed::class, 'feedable');
}
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Domain\Votes\Models;
use App\Models\Model;
use App\Models\User;
class Vote extends Model
{
public function users()
{
return $this->belongsToMany(User::class)->withPivot('payment');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Domain\Votes\Observers;
use App\Domain\Votes\Models\Vote;
use App\Domain\Votes\Services\VoteService;
class VoteObserver
{
public function created(Vote $vote)
{
$mode = nova_get_setting('vote_paid_mode');
// Платный режим
if($mode){
(new VoteService($vote))->accrualPoints();
}else{
(new VoteService($vote))->freeMode();
}
}
}

View File

@@ -0,0 +1,180 @@
<?php
namespace App\Domain\Votes\Services;
use DB;
use Carbon\Carbon;
use App\Models\User;
use App\Domain\Points\Models\Point;
use App\Domain\Points\Enums\DirectionEnum;
use App\Domain\Subscriptions\Models\Subscription;
use App\Domain\Subscriptions\Service\SubscriptionService;
class VoteService
{
public $vote;
public $leaders;
public function __construct($vote)
{
$leader_count = nova_get_setting('vote_leader_count');
$leaders = SubscriptionService::leaders();
$leaders = array_column(array_slice($leaders, 0, $leader_count), 'user_id');
$this->leaders = $leaders;
$this->vote = $vote;
}
public function accrualPoints()
{
DB::beginTransaction();
$procent_site = (int)nova_get_setting('vote_procent_site');
$procent_site = $procent_site / 100;
$procent_top = (int)nova_get_setting('vote_procent_leader');
$procent_top = $procent_top / 100;
$procent_local = (int)nova_get_setting('vote_procent_local_leader');
$procent_local = $procent_local / 100;
$subscriptions = Subscription::with('user.subscribers.subscription')->where('ends_at', '>', Carbon::now())
->where('status', 'complete')->get();
$sum_site = 0;
$sdr_leader_pay = 0;
$sdr_leader_for_all_pay = [];
foreach ($subscriptions as $subscription) {
$user = $subscription->user;
$subscribers = $this->activeSubs($user->subscribers);
// Фильтр лидеров
$subscribersLeader = $subscribers->filter(function ($subscriber) {
return $subscriber->pivot->leader === 1;
});
// Фильтр простых пользователей
$subscribersSimple = $subscribers->filter(function ($subscriber) {
return $subscriber->pivot->leader === 0;
});
$price = $subscription->price;
$to_site = round($price * $procent_site);
$sum_site += $to_site;
$sdr = round($price - $to_site); // сумма для распределения
$sdr_leader_global = round($sdr * $procent_top);
$sdr_leader_local = round($sdr * $procent_local);
$sdr_simple = $sdr - $sdr_leader_global - $sdr_leader_local;
// добавляем лидерам
$sdr_leader_pay += $sdr_leader_global;
//если 0 подписок, но куплена подписка на сайт
// отдаем лидеру 40%, а 60% сайту
if($subscribers->isEmpty()){
$sum_site += ($sdr - $sdr_leader_global); // 20%сайту(вместо локальных) и 40%сайту (вместо простых)
}else {
if ($subscribersLeader->isNotEmpty()) {
//Выплачиваем каждому локальному лидеру
$sdr_parts_local = round($sdr_leader_local / $subscribersLeader->count());
//сохраняем транзакции локальных лидеров
foreach ($subscribersLeader as $subs) {
$sdr_leader_for_all_pay[$subs->id][] = $sdr_parts_local;
}
}else{
$sum_site += $sdr_leader_local; //если у пользователя есть подписки, но он не выбрал лидеров
}
if ($subscribersSimple->isNotEmpty()) {
//Выплачиваем каждому юзеру
$sdr_parts = round($sdr_simple / $subscribersSimple->count());
//сохраняем транзакции простых пользователей
foreach ($subscribersSimple as $subs) {
$sdr_leader_for_all_pay[$subs->id][] = $sdr_parts;
}
}else{
$sum_site += $sdr_simple;
}
}
$this->updateSubs($subscription);
}
$part_for_leader = round($sdr_leader_pay/count($this->leaders));
foreach ($this->leaders as $leader) {
$sdr_leader_for_all_pay[$leader][] = $part_for_leader;
}
$this->payUsers($sdr_leader_for_all_pay);
$this->payForSystemUser($sum_site);
DB::commit();
}
private function payUsers($sdr)
{
$sdr_users_pay = array_map(function ($lines) {
return array_sum($lines);
}, $sdr);
foreach ($sdr_users_pay as $user_pay_id => $sdr_user) {
$this->addPoint($user_pay_id, $sdr_user);
}
}
private function payForSystemUser($sum_site)
{
$system_user_id = User::system()->id;
$this->addPoint($system_user_id, $sum_site);
}
private function addPoint($user_id, $amount)
{
$point = new Point;
$point->user_id = $user_id;
$point->point = $amount;
$point->type = 'votes'; //YSV ENUM!
$point->direction = DirectionEnum::COMING();
$point->save();
$this->vote->users()->attach($user_id, ['payment' => $amount]);
}
private function updateSubs($sub)
{
$sub->status = 'end'; //YSV ENUM!
$sub->save();
}
//проверка на акт. подписки
private function activeSubs($subscribers)
{
return $subscribers->filter(function ($subscriber) {
return optional($subscriber->subscription->first())->ends_at > Carbon::now();
});
}
public function freeMode()
{
$users = SubscriptionService::freeLeaders();
foreach ($users as $leader) {
$this->vote->users()->attach($leader->id, ['payment' => $leader->countVote]);
}
}
}

View File

@@ -0,0 +1,155 @@
<?php
namespace App\Domain\Votes\Services;
use DB;
use Carbon\Carbon;
use App\Models\User;
use App\Domain\Points\Models\Point;
use App\Domain\Points\Enums\DirectionEnum;
use App\Domain\Subscriptions\Models\Subscription;
use App\Domain\Subscriptions\Service\SubscriptionService;
class VoteServiceOld
{
public $vote;
public $leaders;
public function __construct($vote)
{
$leaders = SubscriptionService::leaders();
$leaders = array_column(array_slice($leaders, 0, 2), 'user_id');
$this->leaders = $leaders;
$this->vote = $vote;
}
public function accrualPoints()
{
DB::beginTransaction();
$procent_site = (int)$this->vote->procent_site;
$procent_site = $procent_site / 100;
$procent_top = (int)$this->vote->procent_top;
$procent_top = $procent_top / 100;
$subscriptions = Subscription::with('user.subscribers.subscription')->where('ends_at', '>', Carbon::now())
->where('status', 'complete')->get();
$sum_site = 0;
$sdr_leader_pay = 0;
$sdr_users_pay = [];
foreach ($subscriptions as $subscription) {
$subscribers_simple = collect([]);
$user = $subscription->user;
$subscribers = $this->activeSubs($user->subscribers);
$one_sub_is_leader = $this->oneLeaders($subscribers);
if (! $one_sub_is_leader) {
$subscribers_simple = $subscribers->filter(function ($subscriber) {
return ! in_array($subscriber->id, $this->leaders);
});
}
$price = $subscription->price;
$to_site = $price * $procent_site;
$sum_site += $to_site;
$sdr = round($price - $to_site);
$sdr_leader = round($sdr * $procent_top);
$sdr_simple = $sdr - $sdr_leader;
if ($one_sub_is_leader) {
//выплачиваем весь sdr если чел. подписан на лидеров, и у него больше нет простых
$sdr_leader_pay += $sdr;
} else {
$sdr_leader_pay += $sdr_leader;
}
if ($subscribers_simple->isNotEmpty()) {
//Выплачиваем каждому юзеру
$sdr_parts = round($sdr_simple / $subscribers_simple->count());
//сохраняем транзакции простых пользователей
foreach ($subscribers_simple as $subs) {
$sdr_users_pay[$subs->id][] = $sdr_parts;
}
}
$this->updateSubs($subscription);
}
$this->payForSimpleUser($sdr_users_pay);
$this->payForLeaderUser($sdr_leader_pay);
$this->payForSystemUser($sum_site);
DB::commit();
}
public function payForSystemUser($sum_site)
{
$system_user_id = User::system()->id;
$this->addPoint($system_user_id, $sum_site);
}
//оплата лидеров
public function payForLeaderUser($sdr_leader_pay)
{
$part_for_leader = round($sdr_leader_pay/count($this->leaders));
foreach ($this->leaders as $leader) {
$this->addPoint($leader, $part_for_leader);
}
}
//оплата обычных
public function payForSimpleUser($sdr_users_pay)
{
$sdr_users_pay = array_map(function ($lines) {
return array_sum($lines);
}, $sdr_users_pay);
foreach ($sdr_users_pay as $user_pay_id => $sdr_users) {
$this->addPoint($user_pay_id, $sdr_users);
}
}
public function addPoint($user_id, $amount)
{
$point = new Point;
$point->user_id = $user_id;
$point->point = $amount;
$point->type = 'votes'; //YSV ENUM!
$point->direction = DirectionEnum::COMING();
$point->save();
$this->vote->users()->attach($user_id, ['payment' => $amount]);
}
public function updateSubs($sub)
{
$sub->status = 'end'; //YSV ENUM!
$sub->save();
}
// есть в списке только лидеры
public function oneLeaders($subscribers)
{
if ($subscribers->count() <= count($this->leaders)) {
$contains = $subscribers->filter(function ($subscriber) {
return in_array($subscriber->id, $this->leaders);
});
if ($contains->count() === $subscribers->count()) {
return true;
}
}
return false;
}
//проверка на акт. подписки
public function activeSubs($subscribers)
{
return $subscribers->filter(function ($subscriber) {
return optional($subscriber->subscription->first())->ends_at > Carbon::now();
});
}
}

40
app/Events/FeedAddProcessed.php Executable file
View File

@@ -0,0 +1,40 @@
<?php
namespace App\Events;
use App\Domain\Feeds\Models\Feed;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class FeedAddProcessed
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $feed;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Feed $feed)
{
$this->feed = $feed;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('add-feed-for-readers');
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Events;
use App\Domain\Feeds\Models\Feed;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class FeedRemoveProcessed
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $feed;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Feed $feed)
{
$this->feed = $feed;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('remove-feed-for-readers');
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Events;
use App\Domain\Feeds\Models\Feed;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class FeedUpdateProcessed
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $feed;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Feed $feed)
{
$this->feed = $feed;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('update-feed-for-readers');
}
}

51
app/Exceptions/Handler.php Executable file
View File

@@ -0,0 +1,51 @@
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* @var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
//
}
public function render($request, Throwable $e)
{
$response = parent::render($request, $e);
if ($response->status() === 419) {
return back()->with([
'message' => 'The page expired, please try again.',
]);
}
return $response;
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
class AuthenticatedSessionController extends Controller
{
/**
* Display the login view.
*
* @return \Inertia\Response
*/
public function create()
{
return Inertia::render('Auth/Login');
}
/**
* Handle an incoming authentication request.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
return redirect()->intended(RouteServiceProvider::HOME);
}
/**
* Destroy an authenticated session.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Request $request)
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Controllers\Auth;
use Inertia\Inertia;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
class EmailVerificationPromptController extends Controller
{
/**
* Display the email verification prompt.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function __invoke(Request $request)
{
if($request->user()->hasVerifiedEmail()){
return redirect()->intended(RouteServiceProvider::HOME);
}
return Inertia::render('Auth/VerifyEmail');
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers\Auth;
use Inertia\Inertia;
use Illuminate\View\View;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Password;
use Illuminate\Auth\Events\PasswordReset;
class NewPasswordController extends Controller
{
/**
* Display the password reset view.
*/
public function create(Request $request)
{
return Inertia::render('Auth/ResetPassword', [
'token' => $request->route('token'),
]);
}
/**
* Handle an incoming new password request.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request): RedirectResponse
{
$request->validate([
'token' => ['required'],
'email' => ['required', 'email'],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
$user->forceFill([
'password' => Hash::make($request->password),
'remember_token' => Str::random(60),
])->save();
event(new PasswordReset($user));
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $status == Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->with('status', __($status));
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Http\Controllers\Auth;
use Inertia\Inertia;
use Illuminate\View\View;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Password;
class PasswordResetLinkController extends Controller
{
/**
* Display the password reset link request view.
*/
public function create()
{
return Inertia::render('Auth/ForgotPassword');
}
/**
* Handle an incoming password reset link request.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request): RedirectResponse
{
$request->validate([
'email' => ['required', 'email'],
]);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$status = Password::sendResetLink(
$request->only('email')
);
return back()->with('status', __($status));
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Models\User;
use Inertia\Inertia;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules;
use App\Mail\AfterReigsterToAdmin;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Auth\Events\Registered;
use App\Providers\RouteServiceProvider;
class RegisteredUserController extends Controller
{
/**
* Display the registration view.
*
* @return \Illuminate\View\View
*/
public function create()
{
return Inertia::render('Auth/Register');
}
/**
* Handle an incoming registration request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'first_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => ['required', Rules\Password::defaults()],
]);
$user = User::create([
'first_name' => $request->first_name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
event(new Registered($user));
Auth::login($user);
Mail::to(env('MAIL_ADMIN_EMAIL'))->send(new AfterReigsterToAdmin($user));
return redirect(RouteServiceProvider::HOME);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Verified;
use Illuminate\Foundation\Auth\EmailVerificationRequest;
class VerifyEmailController extends Controller
{
/**
* Mark the authenticated user's email address as verified.
*
* @param \Illuminate\Foundation\Auth\EmailVerificationRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function __invoke(EmailVerificationRequest $request)
{
if ($request->user()->hasVerifiedEmail()) {
return redirect()->intended(
config('app.frontend_url').RouteServiceProvider::HOME.'?verified=1'
);
}
if ($request->user()->markEmailAsVerified()) {
event(new Verified($request->user()));
}
return redirect()->intended(
config('app.frontend_url').RouteServiceProvider::HOME.'?verified=1'
);
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Domain\Feeds\Models\Feed;
use Illuminate\Pagination\Cursor;
use App\Notifications\CommentAdded;
use App\Domain\Comments\Models\Comment;
use Illuminate\Http\Request as HttpRequest;
class CommentController extends Controller
{
public function __construct()
{
// $this->middleware('subs.paid');
}
public function show($feed_id)
{
$count_pagination = 50;
$cursor_request = request('cursor') ?? null;
$feed = Feed::find($feed_id);
if(empty($feed)){
return [
'nextCursor' => null,
'items' => []
];
}
$comments = $feed->comments()
->where('parent_id', null)
->withCount('children')
->with('user:id,first_name,last_name,username,photo_path,color,user_char')->cursorPaginate($count_pagination, ['*'], 'cursor', Cursor::fromEncoded($cursor_request));
$nextCursor = $comments->nextCursor();
if($nextCursor){
$nextCursor = $nextCursor->encode();
}else{
$nextCursor = null;
}
return [
'nextCursor' => $nextCursor,
'items' => $comments->transform(function ($item) {
$item->childrens = [];
$item->closed_children_comments = 1;
$item->created_at_humans = $item->created_at->diffForHumans();
return $item;
})
];
}
public function children($comment_id)
{
$count_pagination = 50;
$cursor_request = request('cursor') ?? null;
$comments = Comment::findOrFail($comment_id)
->children()
->with('user:id,first_name,last_name,username,photo_path,color,user_char', 'answer_to:id,username')
->cursorPaginate($count_pagination, ['*'], 'cursor', Cursor::fromEncoded($cursor_request));
$nextCursor = $comments->nextCursor();
if($nextCursor){
$nextCursor = $nextCursor->encode();
}else{
$nextCursor = null;
}
return [
'nextCursor' => $nextCursor,
'items' => $comments->transform(function ($item) {
$item->created_at_humans = $item->created_at->diffForHumans();
return $item;
})
];
}
public function store(HttpRequest $request, $feed_id)
{
$disabled_notify_main = 0;
$feed = Feed::findOrFail($feed_id);
$body = $request->input('body');
$body = preg_replace('/(?<=\s|^)@\S+/', "", $body);
$body = htmlentities(trim($body));
$to = $request->input('to');
$parent = $request->input('parent');
$comment = new Comment;
$comment->body = $body;
$comment->user_id = auth()->user()->id;
$comment->feed_id = $feed_id;
if($parent){
$comment->parent_id = $parent;
}
if($to){
$comment->to_user_id = $to;
}
$feed->comments()->save($comment);
$comment->setRelation('user', auth()->user());
if($to){
$toUser = User::find($to);
$comment->setRelation('answer_to', $toUser);
if($toUser->id !== auth()->user()->id){
$disabled_notify_main = 1;
$message = [
'user_id' => auth()->user()->id,
'node_id' => $feed_id,
'comment' => $body
];
$toUser->notify(new CommentAdded($message));
}
}
$comment->created_at_humans = $comment->created_at->diffForHumans();
if(empty($parent)){
$comment->childrens = [];
$comment->closed_children_comments = 1;
}
if($feed->user_id !== auth()->user()->id && $disabled_notify_main === 0){
$message = [
'user_id' => auth()->user()->id,
'node_id' => $feed_id,
'comment' => $body
];
$feed->user->notify(new CommentAdded($message));
}
return $comment;
}
public function remove($comment_id)
{
$remove_count = 1;
$comment = Comment::findOrFail($comment_id);
$children_count = $comment->children()->count();
if($children_count){
$comment->children()->forceDelete();
$remove_count = $remove_count + $children_count;
}
$comment->forceDelete();
// Comment::destroy($comment_id);
return $remove_count;
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace App\Http\Controllers;
use App\Domain\Comments\Models\Comment;
use App\Domain\Complaints\Models\CommentComplaint;
use Inertia\Inertia;
use Illuminate\Http\Request;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Complaints\Models\Reason;
use Illuminate\Support\Facades\Redirect;
use App\Domain\Complaints\Models\Complaint;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
class ComplaintController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid');
}
public function index($feed_id)
{
$feed = Feed::findOrFail($feed_id);
if ($feed->user()->is(auth()->user())) {
return Redirect::back();
}
$reasons = Reason::all();
$feed = new FeedQueryBuilder();
$feed = $feed->selectByIds($feed_id)->disablePaginate()->transformGet()->first();
return Inertia::render('Complaint/Index', [
'user' => $feed['user'],
'feed' => $feed,
'reasons' => $reasons,
]);
}
public function store(Request $request)
{
$feed_id = $request->get('feed');
$feed = Feed::findOrFail($feed_id);
if(empty($request->get('reason'))){
return Redirect::back()->with('error', 'Выберите тип жалобы!');
}
$reason_id = $request->get('reason');
$reason = Reason::findOrFail($reason_id);
$complaint = new Complaint;
$complaint->user_id = auth()->user()->id;
$complaint->reason_id = $reason->id;
$complaint->feed_id = $feed->id;
$complaint->save();
// return Redirect::route('feeds.layoutsidebar')->with('success', 'Жалоба успешно отправлена');
return Redirect::back()->with('success', 'Жалоба успешно отправлена');
}
public function commentIndex($comment_id)
{
$comment = Comment::findOrFail($comment_id);
if ($comment->user()->is(auth()->user())) {
return Redirect::back();
}
$reasons = Reason::all();
$user = $comment->user;
$user->name = $user->name;
return Inertia::render('Complaint/IndexComment', [
'user' => $comment->user,
'comment' => $comment,
'reasons' => $reasons,
]);
}
public function commentStore(Request $request)
{
$comment_id = $request->get('comment');
$comment = Comment::findOrFail($comment_id);
if(empty($request->get('reason'))){
return Redirect::back()->with('error', 'Выберите тип жалобы!');
}
$reason_id = $request->get('reason');
$reason = Reason::findOrFail($reason_id);
$complaint = new CommentComplaint;
$complaint->user_id = auth()->user()->id;
$complaint->reason_id = $reason->id;
$complaint->comment_id = $comment->id;
$complaint->save();
return Redirect::back()->with('success', 'Жалоба успешно отправлена');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

View File

@@ -0,0 +1,92 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Mail\FeedbackToAdmin;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Request;
use Illuminate\Http\Request as HttpRequest;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
class DashboardController extends Controller
{
public function __construct()
{
// $this->middleware('subs.paid');
}
public function index()
{
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())->filter()->search(Request::only('search'))->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if($filter === 'hot'){
$feeds = $feeds->sortByDesc('entity.likes')->values();
}
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Dashboard/Index', [
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'nextCursor' => $nextCursor,
'active_filter' => $filter ?? 'new'
]);
}
public function commonSendWriteToUs()
{
return Inertia::render('Auth/Feedback', []);
}
public function sendWriteToUs(HttpRequest $request)
{
$user = auth()->user();
if($user){
$request->validate([
'title' => ['required'],
'body' => ['required'],
]);
$userInfo = (object)[
'userFullName' => $user->name,
'userPhone' => $user->phone,
'userEmail' => $user->email,
'profileUrl' => env('APP_URL') . '/profile/' . $user->username,
'guest' => false
];
}else{
$request->validate([
'title' => ['required'],
'body' => ['required'],
'email' => ['required'],
]);
$userInfo = (object)[
'userEmail' => request()->post('email'),
'guest' => true
];
}
$data = (object) [
'title' => request()->post('title'),
'body' => request()->post('body'),
'userInfo' => $userInfo
];
Mail::to(env('MAIL_ADMIN_EMAIL'))->send(new FeedbackToAdmin($data));
return back()->with('success', 'Сообщение успешно отправлено')->with('status', 'Сообщение успешно отправлено');
}
}

View File

@@ -0,0 +1,234 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Notifications\LikeAdded;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Points\Models\Point;
use App\Notifications\PurchaseAdded;
use Illuminate\Support\Facades\Redirect;
use App\Domain\Points\Enums\DirectionEnum;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Feeds\Service\FeedMediaTransform;
use App\Domain\Subscriptions\Service\SubscriptionService;
class FeedsController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid')->except('comments', 'commentsShowChildren', 'add_view_feed');
}
public function index()
{
$feeds = (new FeedQueryBuilder(auth()->user()->live_feeds()))->enableAdvertising()->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Feed/Index', [
'feeds' => $feeds,
'nextCursor' => $nextCursor,
'active_button' => ''
]);
}
public function onlyImages()
{
$feeds = (new FeedQueryBuilder(auth()->user()->live_feeds()))->enableAdvertising()->addType('image')->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Feed/Index', [
'feeds' => $feeds,
'nextCursor' => $nextCursor,
'active_button' => 'image'
]);
}
public function onlyVideos()
{
$feeds = (new FeedQueryBuilder(auth()->user()->live_feeds()))->enableAdvertising()->addType('video')->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Feed/Index', [
'feeds' => $feeds,
'nextCursor' => $nextCursor,
'active_button' => 'video'
]);
}
public function onlyMusics()
{
$feeds = (new FeedQueryBuilder(auth()->user()->live_feeds()))->enableAdvertising()->addType('music')->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Feed/Index', [
'feeds' => $feeds,
'nextCursor' => $nextCursor,
'active_button' => 'music'
]);
}
public function toggleLike($feed_id)
{
$auth_user = auth()->user();
$feed = Feed::findOrFail($feed_id);
$check = \DB::table('users_feeds_like')->where('user_id', $auth_user->id)->where('feed_id', $feed_id)->first();
// $check_notifications = \DB::table('notifications')
// ->where('notifiable_id', $auth_user->id)
// ->where('entity_once', $feed_id)
// ->where('once', 1)
// ->first();
$auth_user->likes()->toggle([$feed_id]);
if(!$check && $feed->user_id !== $auth_user->id){
$message = [
'user_id' => $auth_user->id,
'node_id' => $feed_id,
];
$feed->user->notify(new LikeAdded($message));
}
return Redirect::back();
}
public function audioLike($media_id)
{
sleep(1);
auth()->user()->audioLike()->toggle([$media_id]);
return Redirect::back();
}
public function purchase($feed_id)
{
\DB::beginTransaction();
$feed = Feed::findOrFail($feed_id);
$price_feed = (int) $feed->price;
$balance = SubscriptionService::calculate(auth()->user()->id);
$check = \DB::table('user_feed_purchase')->where('user_id', auth()->user()->id)->where('feed_id', $feed_id)->first();
if ($check) {
return ['error' => 1, 'msg' => 'Вы уже купили данный продукт'];
}
if ($feed->user()->is(auth()->user())) {
return ['error' => 1, 'msg' => 'Ошибка'];
}
if ($price_feed > $balance) {
return ['error' => 1, 'msg' => 'Недостаточно средств'];
}
$user = auth()->user();
$user->purchases()->attach($feed_id, ['amount' => $price_feed]);
$point = new Point;
$point->user_id = $user->id;
$point->feed_id = $feed->id;
$point->point = $price_feed;
$point->type = 'Покупка - ' . $feed->type; //YSV ENUM!
$point->direction = DirectionEnum::EXPENSE();
$point->save();
$point = new Point;
$point->user_id = $feed->user_id;
$point->feed_id = $feed->id;
$point->point = $price_feed;
$point->type = 'Покупка - ' . $feed->type; //YSV ENUM!
$point->direction = DirectionEnum::COMING();
$point->save();
$new_medias = $this->replace(null, $feed);
$message = [
'user_id' => auth()->user()->id,
'node_id' => $feed->id,
'price' => $price_feed,
];
$feed->user->notify(new PurchaseAdded($message));
\DB::commit();
return $new_medias;
}
public function replace($feed_id = null, $feed = null)
{
if(empty($feed)){
$feed = Feed::findOrFail($feed_id);
}
$preview = '';
$medias = [];
if($feed->is_paid === 1){
$mediaTransform = new FeedMediaTransform($feed);
$mediaTransform = $mediaTransform->paid()->spot();
$preview = $mediaTransform['preview'];
$medias = $mediaTransform['medias'];
}
return ['preview' => $preview, 'collection' => $medias];
}
public function purchase_check($feed_id)
{
$check = \DB::table('user_feed_purchase')->where('user_id', auth()->user()->id)->where('feed_id', $feed_id)->first();
if ($check) {
return 1;
}
return 0;
}
public function add_view_feed($feed_id)
{
if(!auth()->check()){
return 0;
}
$check = \DB::table('users_feeds_view')->where('user_id', auth()->user()->id)->where('feed_id', $feed_id)->first();
if(!$check){
\DB::table('users_feeds_view')->insert([
'user_id' => auth()->user()->id,
'feed_id' => $feed_id
]);
$feed = Feed::findOrFail($feed_id);
$feed->increment('views_count');
return 1;
}else{
return 0;
}
}
public function destroy(Feed $feed)
{
if ($feed->user()->is(auth()->user())) {
$feed->delete();
}
return Redirect::route('profile.user', auth()->user()->username)->with('success', 'Запись успешно удалена!');
}
}

View File

@@ -0,0 +1,165 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
// use Illuminate\Http\Request as HttpRequest;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Http\Requests\ImageFormRequest;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Redirect;
use App\Domain\Tags\Action\CreateTagAction;
use App\Domain\Feeds\Action\CreateFeedAction;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Images\Action\CreateImageAction;
use App\Domain\Images\Action\UpdateImageAction;
use App\Domain\Feeds\Service\FeedMediaTransform;
use App\Domain\Images\DataTransferObjects\ImageData;
class ImagesController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid')->except('show');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addType('image')
->enableAdvertising()
->search(Request::only('search'))
->filter($filter)
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('images.index');
return Inertia::render('Image/Index', [
'nextCursor' => $nextCursor,
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'local_route' => $route,
'active_filter' => $filter ?? 'new'
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return Inertia::render('Image/Create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\ImageFormRequest $request
* @return \Illuminate\Http\Response
*/
public function store(ImageFormRequest $request)
{
$action = new CreateFeedAction(
new CreateImageAction(),
new CreateTagAction(),
);
$imageData = ImageData::fromRequest($request);
$action($imageData);
$msg = 'Изображение успешно загружено и находится на модерации!';
return Redirect::route('profile.user', auth()->user()->username)->with('success', $msg);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($slug)
{
$feed = new FeedQueryBuilder();
$feed = $feed->selectBy('slug', $slug)->disablePaginate()->transformGet()->first();
if(!$feed){
abort(404);
}
return Inertia::render('Image/Show', [
'user' => $feed['user'],
'feed' => $feed,
]);
}
/**
* Show the form for editing the specified resource.
*
* @param string $slug
* @return \Illuminate\Http\Response
*/
public function edit($slug)
{
$feed = Feed::where('slug', $slug)->firstOrFail();
if (!$feed->user()->is(auth()->user())) {
abort(404);
}
$tags = $feed->tags()->pluck('name')->toArray();
$mediaTransformCommon = (new FeedMediaTransform($feed))->default()->spot();
$mediaTransformPaid = (new FeedMediaTransform($feed))->paid()->spot();
return Inertia::render('Image/Edit', [
'feed' => $feed,
'tags' => $tags,
'mediasCount' => count($mediaTransformCommon['medias']),
'mediasCommon' => $mediaTransformCommon['medias'],
'mediasPaid' => $mediaTransformPaid['medias'],
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(ImageFormRequest $request, Feed $feed)
{
$oldStatus = $feed->status;
if (!$feed->user()->is(auth()->user())) {
abort(404);
}
$action = new CreateFeedAction(
new UpdateImageAction($feed),
new CreateTagAction(),
);
$imageData = ImageData::fromRequest($request);
$action($imageData);
$newStatus = $feed->status;
$message = 'Изображение успешно обновлено!';
if($oldStatus === StatusEnum::APPROVED() && $newStatus === StatusEnum::EDITABLE()){
$message = 'Изображение успешно обновлено и находится на модерации!';
}
return Redirect::back()->with('success', $message);
}
}

View File

@@ -0,0 +1,331 @@
<?php
namespace App\Http\Controllers;
use App\Domain\Messenger\Models\ChatRoom;
use App\Domain\Messenger\Models\Message;
use App\Models\User;
use Inertia\Inertia;
use Illuminate\Support\Facades\Request;
use Illuminate\Http\Request as HttpRequest;
use Illuminate\Database\Eloquent\Builder;
class MessengerController extends Controller
{
protected function getSearchByMessage($currentUser, $search)
{
return $currentUser
->chat_rooms()
->orderBy('updated_at', 'desc')
->with(['messsages' => function ($query) use($search) {
$query->where('message', 'ilike', "{$search}%");
}, 'users:id,first_name,last_name,username,photo_path,banner_path,color,user_char'])
->whereHas('messsages', function (Builder $query) use($search) {
$query->where('message', 'ilike', "{$search}%");
})
->get();
}
protected function getSearchByUser($currentUser, $search)
{
return $currentUser
->chat_rooms()
->orderBy('updated_at', 'desc')
->with(['users:id,first_name,last_name,username,photo_path,banner_path,color,user_char', 'messsages'])
->whereHas('users', function (Builder $query) use($search) {
$query->where('first_name', 'ilike', '%'.$search.'%')
->orWhere('last_name', 'ilike', '%'.$search.'%');
})
->get();
}
public function index()
{
// Если пользователь выбирается по гет параметру
$chatSelectUser = null;
$chatSelectUserID = 0;
if($getUsername = request()->get('user')){
$chatSelectUser = User::where('username', $getUsername)->firstOrFail();
$chatSelectUser->name = $chatSelectUser->name;
$chatSelectUserID = $chatSelectUser->id;
}
$search = request()->get('search');
$type = request()->get('type');
$currentUser = auth()->user();
if($search){
if($type == 1){
$chat_rooms = $this->getSearchByMessage($currentUser, $search);
}else{
$chat_rooms = $this->getSearchByUser($currentUser, $search);
}
$chat_rooms->transform(function ($room) {
$message = $room->messsages->first();
$room->latestMessage = $message;
return $room;
});
}else{
$chat_rooms = $currentUser
->chat_rooms()
->orderBy('updated_at', 'desc')
->with('latestMessage', 'users:id,first_name,last_name,username,photo_path,banner_path,color,user_char')
->get();
}
$rooms = $chat_rooms->map(function ($room) use ($currentUser, $chatSelectUserID) {
$is_my_message = false;
$classActive = false;
if($room->latestMessage->user_id === $currentUser->id){
$is_my_message = true;
}
$message = $room->latestMessage->message;
$updated_at_human = $room->latestMessage->created_at->diffForHumans();
$updated_at = $room->latestMessage->created_at->format('U');
$correspond = $room->users->where('id', '<>', $currentUser->id)->first();
unset($correspond->pivot);
$correspond->name = $correspond->name;
if($chatSelectUserID === $correspond->id){ // делаем активным
$classActive = true;
}
return [
'id' => $room->id,
'is_freeze' => $room->is_freeze,
'classActive' => $classActive,
'is_my_message' => $is_my_message,
'message' => $message,
'is_reading' => $room->latestMessage->is_reading,
'updated_at' => $updated_at,
'updated_at_human' => $updated_at_human,
'correspond' => $correspond->toArray(),
];
});
if($chatSelectUserID){
$checkActiveRoom = $rooms->contains(function ($item) {
return $item['classActive'] === true;
});
if(!$checkActiveRoom){
$globalRoomUser = $this->isRoomCreate($chatSelectUserID);
if($globalRoomUser){
$globalRoomUser->load('latestMessage');
$is_my_message = false;
if($globalRoomUser->latestMessage->user_id === auth()->user()->id){
$is_my_message = true;
}
$new_room = [
'id' => $globalRoomUser->id,
'is_freeze' => $globalRoomUser->is_freeze,
'classActive' => true,
'is_my_message' => $is_my_message,
'message' => $globalRoomUser->latestMessage->message,
'is_reading' => $globalRoomUser->latestMessage->is_reading,
'updated_at' => $globalRoomUser->updated_at->format('U'),
'updated_at_human' => $globalRoomUser->updated_at->diffForHumans(),
'correspond' => $chatSelectUser->only(['id','name','first_name','last_name','photo_path','banner_path','color','user_char', 'username']),
];
$rooms[] = $new_room;
}
}
$rooms = $rooms->sortByDesc('classActive')->values();
}
return Inertia::render('Messenger/Index', [
'rooms' => $rooms,
'roomSearch' => $search,
]);
}
public function show($id)
{
$room = ChatRoom::findOrFail($id);
$search = request()->get('search');
$messages = $room->messsages()->with('user:id,first_name,photo_path,color,user_char')->orderBy('id');
if($search){
$messages = $messages->where('message', 'ilike', "{$search}%");
}
$messages = $messages->cursorPaginate(50);
$nextCursor = get_cursor_hash($messages);
$messages->each(function ($message) {
if($message->is_reading === false && $message->user_id != auth()->user()->id){
$message->is_reading = true;
$message->save();
}
$message->group = $message->created_at->format('d.m.Y');
$message->created = $message->created_at->format('H:i');
return $message;
});
$messages = $messages->groupBy(function ($val) {
return \Carbon\Carbon::parse($val->created_at)->format('d.m.Y');
});
return ['records' => $messages, 'cursor' => $nextCursor];
}
public function store(HttpRequest $request)
{
$message = $request->input('params.message');
$chat_room_id = $request->input('params.room');
$status = $this->createMessage($message, $chat_room_id);
if($status === false){
return null;
}
return $status;
}
public function storeFromProfile(HttpRequest $request)
{
$message = $request->input('message');
$chat_room_id = $request->input('chat_room');
$status = $this->createMessage($message, $chat_room_id);
if($status === false){
return redirect()->back()->with('error', 'Вы не можете отправить сообщение данному пользователю');
}
return redirect()->back()->with('success', 'Сообщение успешно отправлено!');
}
protected function createMessage($text, $chat_room_id)
{
$user = auth()->user();
$chatRoom = ChatRoom::find($chat_room_id);
if($chatRoom->is_freeze){
return false;
}
$message = new Message;
$message->message = $text;
$message->user_id = $user->id;
$message->chat_room_id = $chat_room_id;
$message->save();
$chatRoom->touch();
$message->created = $message->created_at->format('H:i');
$message->updated_at_room_human = $message->created_at->diffForHumans();
$message->updated_at_room = $message->created_at->format('U');
$message->group = $message->created_at->format('d.m.Y');
$message->keyGroupDate = $message->created_at->format('d.m.Y');
$message->user = $user->only(['id','first_name','photo_path','color','user_char']);
return $message;
}
public function checkRoom(HttpRequest $request)
{
$userId = $request->input('params.user');
$room = $this->isRoomCreate($userId);
return $room ? $room->id : 0;
}
protected function isRoomCreate($userId)
{
return auth()->user()->chat_rooms()->whereHas('users', function (Builder $query) use($userId) {
$query->where('id', $userId);
})->first();
}
public function createRoom(HttpRequest $request)
{
$message = $request->input('message');
$user_id = $request->input('user_id');
$existBannedUsers = $this->getBannedUser($user_id);
if($existBannedUsers){
return redirect()->back()->with('error', 'Вы не можете отправить сообщение данному пользователю');
}
$room = new ChatRoom;
$room->save();
$room->users()->attach([$user_id, auth()->user()->id]);
$this->createMessage($message, $room->id);
return redirect()->back()->with('success', 'Сообщение успешно отправлено!');
}
public function freezeRoom(HttpRequest $request)
{
$room_id = $request->input('room');
$room = ChatRoom::find($room_id);
$roomUsers = $room->users;
$isAuthUserExist = $roomUsers->contains(fn($user) => $user->id === auth()->user()->id);
$correspond = $roomUsers->where('id', '<>', auth()->user()->id)->first();
if(!$isAuthUserExist){
return redirect()->back()->with('error', 'Доступ запрещен');
}
// добавляем пользователя
$status = auth()->user()->bannedUsers()->toggle([$correspond->id]);
// проверяем есть ли пользователя из чата в черном списке, если есть замораживаем чат
$existBannedUsers = $this->getBannedUser($correspond->id);
if($existBannedUsers){ //disable touch update_at column
\DB::table('chat_rooms')->where('id', $room->id)->update(['is_freeze' => true]);
}else{
\DB::table('chat_rooms')->where('id', $room->id)->update(['is_freeze' => false]);
}
$msg = 'Пользователь успешно удален из чернго списка';
if(count($status['attached'])){
$msg = 'Пользователь успешно добавлен в черный список';
}
return redirect()->back()->with('success', $msg);
}
public function checkBannedUser(HttpRequest $request)
{
$correspond_id = $request->input('params.user');
$partnerIsBanned = \DB::table('user_banned')
->where('user_id', auth()->user()->id)
->where('banned_user_id', $correspond_id)->count();
if($partnerIsBanned){
return ['banned' => true];
}
return ['banned' => false];
}
public function leaveRoom(HttpRequest $request)
{
$room_id = $request->input('room');
$room = ChatRoom::find($room_id);
$room->users()->detach(auth()->user()->id);
return redirect()->back()->with('success', 'Успешно покинули беседу');
}
public function removeMessage($id)
{
$message = Message::findOrFail($id);
$message->delete();
return ['success' => true];
}
protected function getBannedUser($correspondId)
{
return \DB::table('user_banned')
->where('user_id', auth()->user()->id)
->where('banned_user_id', $correspondId)
->orWhere(function($query) use($correspondId) {
$query->where('user_id', $correspondId)
->where('banned_user_id', auth()->user()->id);
})->count();
}
}

View File

@@ -0,0 +1,326 @@
<?php
namespace App\Http\Controllers;
use YooKassa\Client;
use Illuminate\Http\Request;
use App\Domain\Points\Models\Point;
use App\Domain\Payments\Models\Withdrawal;
use App\Domain\Points\Enums\DirectionEnum;
use App\Domain\PaymentGateway\Services\QiwiService;
use App\Domain\PaymentGateway\Services\UnitpayService;
use App\Domain\PaymentGateway\Services\YookassaService;
use App\Domain\PaymentGateway\Models\PaymentGatewayOrder;
use App\Domain\PaymentGateway\Services\InterkassaService;
use App\Domain\Subscriptions\Service\SubscriptionService;
class MoneyController extends Controller
{
public function startProcess(Request $request)
{
$this->validate($request, [
'sum' => 'required|integer|numeric',
]);
$sum = (int) abs($request->input('sum'));
$amount = round(($sum * 0.035) + $sum, 1);
$order = PaymentGatewayOrder::yookassa($sum);
$order_number = ['order_number' => $order->number];
$point = new Point;
$point->user_id = auth()->user()->id;
$point->point = $sum;
$point->type = 'Ожидание поступления';
$point->direction = DirectionEnum::PENDING();
$point->meta = json_encode($order_number);
$point->save();
return redirect(YookassaService::payments_link($amount, $order, auth()->user()));
}
// public function startProcess()
// {
// $amount = filter_input(INPUT_GET, 'sum', FILTER_VALIDATE_INT);
// if(empty($amount)){
// return redirect()->back();
// }
// $order = PaymentGatewayOrder::yookassa($amount);
// return redirect(YookassaService::payments_link($amount, $order, auth()->user()));
// }
public function checkPointPay($id)
{
$point = Point::findOrFail($id);
if($point->direction != 2){
return redirect()->route('setting.money')->with('error', 'Ошбика');
}
$order_number = json_decode($point->meta);
if(empty($order_number)){
return redirect()->route('setting.money')->with('error', 'Ошбика');
}
$order = PaymentGatewayOrder::where('number', $order_number->order_number)->first();
if(empty($order)){
return redirect()->route('setting.money')->with('error', 'Ошбика');
}
if($order->status !== 0){
return redirect()->route('setting.money')->with('error', 'Ошбика');
}
$YOOKASSA_SHOP_ID = env('YOOKASSA_SHOP_ID');
$YOOKASSA_KEY = env('YOOKASSA_KEY');
$client = new Client();
$client->setAuth($YOOKASSA_SHOP_ID, $YOOKASSA_KEY);
$payment = $client->getPaymentInfo($order->system_payment_id);
if ($payment->getStatus() === "succeeded")
{
$order->status = 1;
$order->save();
$point->point = $order->amount;
$point->type = 'Пополнение счета: ' . $order->type . ' # ' . $order->id;
$point->direction = DirectionEnum::COMING();
$point->save();
return redirect()->route('setting.money')->with('success', 'Счет успешно пополнен!');
}
else{
PaymentGatewayOrder::destroy($order->id);
Point::destroy($point->id);
return redirect()->route('setting.money')->with('error', 'Платеж не прошел. Попробуйте еще или выберите другой способ оплаты');
}
}
public function paymentStatus($number)
{
$order = PaymentGatewayOrder::where('number', $number)->firstOrFail();
if($order->status !== 0){
return redirect()->to('/');
}
$YOOKASSA_SHOP_ID = env('YOOKASSA_SHOP_ID');
$YOOKASSA_KEY = env('YOOKASSA_KEY');
$client = new Client();
$client->setAuth($YOOKASSA_SHOP_ID, $YOOKASSA_KEY);
$payment = $client->getPaymentInfo($order->system_payment_id);
$point = Point::where('meta->order_number', $number)->first();
if(empty($point)){
$point = new Point;
$point->user_id = auth()->user()->id;
}
if ($payment->getStatus() === "succeeded")
{
$order->status = 1;
$order->save();
$point->point = $order->amount;
$point->type = 'Пополнение счета: ' . $order->type . ' # ' . $order->id;
$point->direction = DirectionEnum::COMING();
$point->save();
return redirect()->route('setting.money')->with('success', 'Счет успешно пополнен!');
}
else{
PaymentGatewayOrder::destroy($order->id);
Point::destroy($point->id);
return redirect()->route('setting.money')->with('error', 'Платеж не прошел. Попробуйте еще или выберите другой способ оплаты');
}
}
// public function qiwiStatus($number)
// {
// $YOOKASSA_SHOP_ID = env('YOOKASSA_SHOP_ID');
// $YOOKASSA_KEY = env('YOOKASSA_KEY');
// $client = new Client();
// $client->setAuth($YOOKASSA_SHOP_ID, $YOOKASSA_KEY);
// $payment = $client->getPaymentInfo($number);
// dd($payment);
// $SECRET_KEY = env('QIWI_SECRET');
// $order = PaymentGatewayOrder::where('number', $number)->firstOrFail();
// if($order->status !== 0){
// return redirect()->to('/');
// }
// $billPayments = new \Qiwi\Api\BillPayments($SECRET_KEY);
// $response = $billPayments->getBillInfo($number);
// if ($response['status']['value'] === "PAID")
// {
// $order->status = 1;
// $order->save();
// $point = new Point;
// $point->user_id = auth()->user()->id;
// $point->point = $order->amount;
// $point->type = 'Пополнение счета: ' . $order->type . ' # ' . $order->id;
// $point->direction = DirectionEnum::COMING();
// $point->save();
// return redirect()->route('setting.money')->with('success', 'Счет успешно пополнен!');
// }
// else if ($response['status']['value'] === "WAITING")
// {
// echo "Ваш платеж в обработке \n Не закрывайте страницу и попробуйте обновить страницу позже";
// die;
// }
// PaymentGatewayOrder::destroy($order->id);
// $msg_error = 'Заказ завершен с ошибкой';
// if($response['status']['value'] === "REJECTED"){
// $msg_error .= ' - Счет отклонен';
// }
// return redirect()->route('setting.money')->with('error', $msg_error);
// }
public function unitpayStatus()
{
dd(request()->all());
}
public function interkassa()
{
$amount = filter_input(INPUT_GET, 'ik_am', FILTER_VALIDATE_INT);
if(empty($amount)){
return redirect()->back();
}
$order = PaymentGatewayOrder::interkassa($amount);
return redirect(InterkassaService::payments_link($amount, $order->id));
}
public function interkassaStatus()
{
$ik_co_id = request()->ik_co_id; // Идентификатор кассы
$ik_inv_id = request()->ik_inv_id; // Идентификатор платежа в системе Интеркасса
$ik_inv_st = request()->ik_inv_st; // Состояние платежа. - success; fail
$ik_pm_no = request()->ik_pm_no; // Номер заказа. example - ID_4233
if($ik_inv_st === 'success'){
$order = PaymentGatewayOrder::findOrFail($ik_pm_no);
if($order->status === 1){
return redirect()->back();
}
$order->status = 1;
$order->system_payment_id = $ik_inv_id;
$order->save();
$point = new Point;
$point->user_id = auth()->user()->id;
$point->point = $order->amount;
$point->type = 'Пополнение счета: ' . $order->type . ' # ' . $order->id;
$point->direction = DirectionEnum::COMING();
$point->save();
return redirect()->route('setting.money')->with('success', 'Счет успешно пополнен!');
}
return $this->fails($ik_pm_no, $ik_inv_st);
}
protected function fails($order_id, $status)
{
PaymentGatewayOrder::destroy($order_id);
$msg_error = 'Заказ завершен с ошибкой';
if($status === 'canceled'){
$msg_error = 'Заказ отменен';
}
return redirect()->route('setting.money')->with('error', $msg_error);
}
public function payouts()
{
$amount = request()->amount;
$user = auth()->user();
// $bankRequisites = $user->bank_requisites->first();
if(!$user->isVerifiedForWithdrawal()){
return redirect()->back()->with('error', 'Нужно верифицировать аккаунт, загрузить копию паспорта и ввести данные бик, инн, расчетный счет');
// return redirect()->back()->with('error', 'Нужно верифицировать ваш номер телефона');
}
// if(empty($bankRequisites)){
// return redirect()->back()->with('error', 'Заполните платежные реквизиты');
// }
$balance = SubscriptionService::calculate(auth()->user()->id);
if ($amount > $balance) {
return redirect()->back()->with('error', 'Недостаточно средств для вывода');
}
if($user->status == 1 || $user->status == 2){
if (!Withdrawal::canRequestWithdrawalPhysical($user->id, $amount)) {
return redirect()->back()->with('error', 'Превышен лимит выплат за текущий месяц (12000)');
}
}else{
if (!Withdrawal::canRequestWithdrawalLegal($user->id, $amount)) {
return redirect()->back()->with('error', 'Превышен лимит выплат за текущий месяц (150000)');
}
}
// $requisites = $bankRequisites->requisites;
// $detailsDescr[] = 'Тип: по номеру телефона';
// $detailsDescr[] = 'Номер телефона: ' . $user->phone;
$detailsDescr[] = 'Тип: Банк';
// $detailsDescr[] = 'Номер карты: ' . $bankRequisites->number;
$detailsDescr = implode(PHP_EOL, $detailsDescr);
$point = new Point;
$point->user_id = auth()->user()->id;
$point->point = $amount;
$point->type = 'Вывод средств (ожидает обработки)'; //YSV ENUM!
$point->direction = DirectionEnum::EXPENSE();
$point->save();
$withdrawal = new Withdrawal;
$withdrawal->point()->associate($point);
$withdrawal->user()->associate(auth()->user());
$withdrawal->requisites_id = 1;
// $withdrawal->requisites()->associate($requisites);
$withdrawal->amount = $amount;
$withdrawal->history_payment_details = $detailsDescr;
$withdrawal->save();
return redirect()->back()->with('success', 'Запрос на вывод денег успешно отправлен!');
}
}

View File

@@ -0,0 +1,221 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Http\Requests\MusicFormRequest;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Database\Eloquent\Builder;
use App\Domain\Tags\Action\CreateTagAction;
use App\Domain\Feeds\Action\CreateFeedAction;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Musics\Action\CreateMusicAction;
use App\Domain\Musics\Action\UpdateMusicAction;
use App\Domain\Feeds\Service\FeedMediaTransform;
use App\Domain\Musics\DataTransferObjects\MusicData;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class MusicsController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid')->except('loadedPlaylist', 'favoritePlaylist', 'show');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addType('music')
->search(Request::only('search'))
->enableAdvertising()
->filter($filter)
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('musics.index');
return Inertia::render('Music/Feed', [
'nextCursor' => $nextCursor,
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'local_route' => $route,
'active_filter' => $filter ?? 'new'
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return Inertia::render('Music/Create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(MusicFormRequest $request)
{
$action = new CreateFeedAction(
new CreateMusicAction(),
new CreateTagAction(),
);
$musicData = MusicData::fromRequest($request);
$action($musicData);
$msg = 'Музыка успешно загружена и находится на модерации!';
return Redirect::route('profile.user', auth()->user()->username)->with('success', $msg);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($slug)
{
$feed = new FeedQueryBuilder();
$feed = $feed->selectBy('slug', $slug)->disablePaginate()->transformGet()->first();
if(!$feed){
abort(404);
}
return Inertia::render('Music/Show', [
'user' => $feed['user'],
'feed' => $feed,
]);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($slug)
{
$feed = Feed::where('slug', $slug)->firstOrFail();
if (!$feed->user()->is(auth()->user())) {
abort(404);
}
$tags = $feed->tags()->pluck('name')->toArray();
$mediaTransform = (new FeedMediaTransform($feed))->default();
$mediaPreview = $mediaTransform->getPreviewObject();
$mediaTransformCommon = $mediaTransform->spot();
$mediaTransformPaid = (new FeedMediaTransform($feed))->paid()->spot();
return Inertia::render('Music/Edit', [
'feed' => $feed,
'tags' => $tags,
'mediaPreview' => $mediaPreview,
'mediasCount' => count($mediaTransformCommon['medias']),
'mediasCommon' => $mediaTransformCommon['medias'],
'mediasPaid' => $mediaTransformPaid['medias'],
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(MusicFormRequest $request, Feed $feed)
{
$oldStatus = $feed->status;
if (!$feed->user()->is(auth()->user())) {
abort(404);
}
$action = new CreateFeedAction(
new UpdateMusicAction($feed),
new CreateTagAction(),
);
$musicData = MusicData::fromRequest($request);
$action($musicData);
$newStatus = $feed->status;
$message = 'Аудио файл успешно обновлен!';
if($oldStatus === StatusEnum::APPROVED() && $newStatus === StatusEnum::EDITABLE()){
$message = 'Аудио файл успешно обновлен и находится на модерации!';
}
return Redirect::back()->with('success', $message);
}
public function loadedPlaylist()
{
$musics = Media::whereHasMorph(
'model',
[Feed::class],
function (Builder $query) {
$query->where('user_id', auth()->user()->id)->where('type', 'musics');
}
)->where('collection_name', '<>', 'preview')->orderBy('id', 'desc')->cursorPaginate(10);
$cursor = get_cursor_hash($musics);
$musics_collection = [];
$musics->each(function ($media) use (&$musics_collection) {
$musics_collection[] = [
'url' => $media->getFullUrl(),
'name' => $media->name,
'playing' => false,
'time' => $media->getCustomProperty('time'),
'id' => $media->id,
];
});
return ['collection' => $musics_collection, 'cursor' => $cursor];
}
public function favoritePlaylist()
{
$audios = auth()->user()->audioLike()->cursorPaginate(10);
$cursor = get_cursor_hash($audios);
$musics_collection = [];
$audios->each(function ($media) use (&$musics_collection) {
$musics_collection[] = [
'url' => $media->getFullUrl(),
'name' => $media->name,
'playing' => false,
'liked' => true,
'time' => $media->getCustomProperty('time'),
'id' => $media->id,
];
});
return ['collection' => $musics_collection, 'cursor' => $cursor];
}
}

View File

@@ -0,0 +1,266 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Inertia\Inertia;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Request;
use Illuminate\Database\Eloquent\Builder;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Users\Service\ProfileDataService;
use App\Domain\Users\DataTransferObjects\UserData;
use App\Domain\Subscriptions\Service\SubscriptionService;
use Carbon\Carbon;
class ProfileController extends Controller
{
public function __construct()
{
abort_if(Str::contains(request()->url(), 'inner_systemuser_api'), 404);
$this->middleware('subs.paid')->except('profile');
}
public function profile($username)
{
$user = User::where('username', $username)->firstOrFail();
$authUserActiveSubscription = nova_get_setting('vote_paid_mode') ? SubscriptionService::activeSubscription() : true;
$packet = null;
$packageCompleted = false;
if($user->private && auth()->user()){
$packet = $user->customPackage;
if($packet){
$check = \DB::table('users_package_customers')
->where('user_id', $user->id)
->where('customer_id', auth()->user()->id)
->where('package_id', $packet->id)
->where('time_end', '>', now())
->count();
$packageCompleted = $check > 0 ? true : false;
}
}
$userData = UserData::fromModel($user);
if($userData->is_auth_user){
$feeds = (new FeedQueryBuilder($user->feeds()))->enableAdvertising()->disableActiveFeed()->order()->build();
}else{
$feeds = (new FeedQueryBuilder($user->feeds()))->enableAdvertising()->order()->build();
}
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$profileData = ProfileDataService::get($user);
// $testPeriod = auth()->user()->testPeriodCheck();
if(auth()->user()){
$limitLeader = auth()->user()->subscribers()->where('leader', 1)->count() === nova_get_setting('vote_leader_count');
}else{
$limitLeader = false;
}
return Inertia::render('Profile/Index', [
// 'testPeriod' => $testPeriod,
'user' => array_merge([
'about' => $user->about,
'is_sub' => $user->is_sub,
], $userData->toArray()),
'packet' => $packet,
'authUserActiveSubscription' => $authUserActiveSubscription,
'packageCompleted' => $packageCompleted,
'feeds' => $feeds,
'nextCursor' => $nextCursor,
'limitLeader' => $limitLeader,
'is_leader' => $profileData->is_leader,
'close_account' => $profileData->close_account,
'counts' => [
'feeds' => $profileData->count_feeds,
'subscribers' => $profileData->count_subscribers,
'readers' => $profileData->count_readable,
]
]);
}
public function profileReaders($username)
{
$user = User::where('username', $username)->firstOrFail();
$limitLeader = auth()->user()->subscribers()->where('leader', 1)->count() === nova_get_setting('vote_leader_count');
$profileData = ProfileDataService::get($user);
$packageCompleted = false;
$authUserActiveSubscription = nova_get_setting('vote_paid_mode') ? SubscriptionService::activeSubscription() : true;
if($user->private){
$packet = $user->customPackage;
if($packet){
$check = \DB::table('users_package_customers')
->where('user_id', $user->id)
->where('customer_id', auth()->user()->id)
->where('package_id', $packet->id)
->where('time_end', '>', now())
->count();
$packageCompleted = $check > 0 ? true : false;
}
}
$myPaidListSubscribeTo = \DB::table('users_package_customers')
->latest()
->where('customer_id', auth()->user()->id)->get()->groupBy('user_id');
$myPaidListSubscribeTo = $myPaidListSubscribeTo->map(function($item){
$first = $item->first();
$first->expired = Carbon::parse($first->time_end) < now();
return Carbon::parse($first->time_end) < now();
});
// dd($myPaidListSubscribeTo);
$leader = Request::get('leader');
if($leader === '1'){
$readers = $user->subscribersOn();
}elseif ($leader === '0') {
$readers = $user->subscribersOff();
}else{
$readers = $user->subscribers();
}
$readers = $readers->filter(Request::only('search'))
->orderBy('id', 'desc')
->cursorPaginate(User::PAGINATE);
$nextCursor = get_cursor_hash($readers);
$readers->transform(function ($user) {
return array_merge([
'is_leader' => (boolean) $user->pivot->leader,
], UserData::fromModel($user)->toArray());
});
if(request()->wantsJson()){
return ['collections' => $readers->items(), 'next' => $nextCursor];
}
return Inertia::render('Profile/Readers', [
'nextCursor' => $nextCursor,
'user' => array_merge([
'about' => $user->about,
'is_sub' => $user->is_sub,
], UserData::fromModel($user)->toArray()),
'packageCompleted' => $packageCompleted,
'filters' => Request::all('search', 'leader'),
'readers' => $readers->items(),
'limitLeader' => $limitLeader,
'authUserActiveSubscription' => $authUserActiveSubscription,
'is_leader' => $profileData->is_leader,
'close_account' => $profileData->close_account,
'myPaidListSubscribeTo' => $myPaidListSubscribeTo,
'counts' => [
'feeds' => $profileData->count_feeds,
'subscribers' => $profileData->count_subscribers,
'readers' => $profileData->count_readable,
]
]);
}
public function profileSubs($username)
{
$user = User::where('username', $username)->firstOrFail();
$limitLeader = auth()->user()->subscribers()->where('leader', 1)->count() === nova_get_setting('vote_leader_count');
$profileData = ProfileDataService::get($user);
$sub = Request::get('sub');
$authUserActiveSubscription = nova_get_setting('vote_paid_mode') ? SubscriptionService::activeSubscription() : true;
$packageCompleted = false;
if($user->private){
$packet = $user->customPackage;
if($packet){
$check = \DB::table('users_package_customers')
->where('user_id', $user->id)
->where('customer_id', auth()->user()->id)
->where('package_id', $packet->id)
->where('time_end', '>', now())
->count();
$packageCompleted = $check > 0 ? true : false;
}
}
if($sub !== null){
$query = '';
$typeSub = $sub === '1' ? '<>' : '=';
$subscribers = $user->subscriber_reverse()
->withCount([
'subscriber_reverse as pizda' => function (Builder $builder) use (&$query) {
$query = $builder;
$query->where('user_id', auth()->user()->id);
},
])
->whereRaw("({$query->toSql()}) {$typeSub} ?", [$user->id, 0])
->filter(Request::only('search'))
->orderBy('id', 'desc')
->cursorPaginate(User::PAGINATE);
$subscribers->transform(function ($user) use ($sub) {
return array_merge([
'is_sub' => (boolean) $sub,
], UserData::fromModel($user)->toArray());
});
}else{
$subscribers = $user->subscriber_reverse()
->withCount(['subscriber_reverse as is_sub' => function (Builder $query) {
$query->where('user_id', auth()->user()->id);
}])
->withCasts(['is_sub' => 'boolean'])
->filter(Request::only('search'))
->orderBy('id', 'desc')
->cursorPaginate(User::PAGINATE);
$subscribers->transform(function ($user) {
return array_merge([
'is_sub' => $user->is_sub,
], UserData::fromModel($user)->toArray());
});
}
$nextCursor = get_cursor_hash($subscribers);
if(request()->wantsJson()){
return ['collections' => $subscribers->items(), 'next' => $nextCursor];
}
return Inertia::render('Profile/Subs', [
'user' => array_merge([
'about' => $user->about,
'is_sub' => $user->is_sub,
], UserData::fromModel($user)->toArray()),
'packageCompleted' => $packageCompleted,
'authUserActiveSubscription' => $authUserActiveSubscription,
'filters' => Request::all('search', 'sub'),
'limitLeader' => $limitLeader,
'is_leader' => $profileData->is_leader,
'subscribers' => $subscribers->items(),
'close_account' => $profileData->close_account,
'counts' => [
'feeds' => $profileData->count_feeds,
'subscribers' => $profileData->count_subscribers,
'readers' => $profileData->count_readable,
]
]);
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Feeds\Service\FeedMediaTransform;
class PurchaseController extends Controller
{
public function index()
{
$user = auth()->user();
$purchases_feeds = new FeedQueryBuilder($user->purchases()->withTrashed());
$purchases_feeds = $purchases_feeds->withFeedable()->feed->cursorPaginate(FeedQueryBuilder::PAGINATION_COUNT);
$nextCursor = get_cursor_hash($purchases_feeds);
$feeds = [];
foreach ($purchases_feeds as $purchases_feed) {
$mediaTransform = (new FeedMediaTransform($purchases_feed))->default();
$date = [
'price' => $purchases_feed->pivot->amount,
'purchase_date' => $purchases_feed->pivot->created_at->format('Y-m-d'),
'preview' => $mediaTransform->getPreview(),
'id' => $purchases_feed->id,
'type' => $purchases_feed->type,
];
$feeds[] = $date;
}
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Settings/SettingsPurchases', [
'nextCursor' => $nextCursor,
'feeds' => $feeds,
]);
}
public function show($id)
{
$purchases_feed = new FeedQueryBuilder(auth()->user()->purchases()->withTrashed());
$purchases_feed = $purchases_feed->selectByIds($id)->withFeedable()->withUser()->feed->firstOrFail();
$seller = $purchases_feed->user;
$seller->name = $seller->name;
$mediaTransformCommon = (new FeedMediaTransform($purchases_feed))->default()->spot();
$mediaTransformPaid = (new FeedMediaTransform($purchases_feed))->paid()->spot();
$purchase = [
'id' => $purchases_feed->id,
'title' => $purchases_feed->title,
'body' => $purchases_feed->body,
'type' => $purchases_feed->type,
'price' => $purchases_feed->pivot->amount,
'purchase_date' => $purchases_feed->pivot->created_at->format('Y-m-d'),
'preview' => $mediaTransformCommon['preview'],
'common_medias' => $mediaTransformCommon['medias'],
'paid_medias' => $mediaTransformPaid['medias'],
];
return Inertia::render('Settings/SettingsPurchasesFile', [
'purchase' => $purchase,
'seller' => $seller,
]);
}
public function downloadPurchases($id)
{
$purchases_feed = new FeedQueryBuilder(auth()->user()->purchases()->withTrashed());
$purchases_feed = $purchases_feed->selectByIds($id)->withFeedable()->feed->firstOrFail();
$mediaTransformPaid = (new FeedMediaTransform($purchases_feed))->getFullPath()->paid()->spot();
$purchase_date = $purchases_feed->pivot->created_at->format('Y-m-d');
$zip_file = "purchase-{$purchases_feed->type}-{$purchase_date}.zip";
$zip = new \ZipArchive();
$zip->open($zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
foreach ($mediaTransformPaid['medias'] as $paid_media) {
$zip->addFile($paid_media['url'], basename($paid_media['url']));
}
$zip->close();
//unlink(public_path($zip_file));
return response()->download($zip_file);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Controllers;
use App\Domain\Payments\Models\Requisites;
use App\Domain\Payments\Models\BankRequisites;
class RequisitesController extends Controller
{
public function updateBank()
{
$user = auth()->user();
$number = request()->number;
$bankRequisites = $user->bank_requisites->first();
if(!$bankRequisites){
$bankRequisites = new BankRequisites;
$bankRequisites->user()->associate(auth()->user());
$bankRequisites->number = $number;
$bankRequisites->save();
$requisites = new Requisites;
$requisites->user()->associate(auth()->user());
$bankRequisites->requisites()->save($requisites);
}else{
$bankRequisites->number = $number;
$bankRequisites->save();
}
return redirect()->back()->with('success', 'Реквизиты успешно обновлены!');
}
}

View File

@@ -0,0 +1,376 @@
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use App\Models\User;
use Inertia\Inertia;
use Illuminate\Http\Request as HttpRequest;
use App\Domain\Subscriptions\Models\Package;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Subscriptions\Service\SubscriptionService;
class SettingController extends Controller
{
const NOTIFICATION_THRESHOLD = 20;
public function index()
{
$user = auth()->user();
return Inertia::render('Settings/SettingsProfile', [
'user' => [
'id' => $user->id,
'name' => $user->name,
'username' => $user->username,
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'email' => $user->email,
'user_char' => $user->user_char,
'color' => $user->color,
'sex' => $user->sex,
'type' => $user->type,
'phone' => $user->phone,
'date_of_birth' => $user->date_of_birth,
'photo_path' => $user->photo_path,
'banner_path' => $user->banner_path,
'about' => $user->about,
'private' => $user->private,
'inn' => $user->inn,
'checking_account' => $user->checking_account,
'bik' => $user->bik,
// 'allow_adult_content' => $user->allow_adult_content,
],
]);
}
public function notify()
{
auth()->user()->unreadNotifications()->update(['read_at' => Carbon::now()]);
$notifications = auth()->user()
->notifications()
->latest()
->take(self::NOTIFICATION_THRESHOLD)
->get();
$notifications_transform = [];
foreach ($notifications as $notification) {
$d = [];
$data = $notification->data;
if($notification->notifiable_type === User::class){
if($notification->type === 'App\Notifications\LikeAdded'){
$d['type'] = 'like';
}
if($notification->type === 'App\Notifications\CommentAdded'){
$d['type'] = 'comment';
}
if($notification->type === 'App\Notifications\Subscribed'){
$d['type'] = 'subs';
}
if($notification->type === 'App\Notifications\LeaderChoice'){
$d['type'] = 'leader';
}
if($notification->type === 'App\Notifications\UserCustomPaidSubscription'){
$d['type'] = 'custom-paid-subs';
}
if($notification->type === 'App\Notifications\PurchaseAdded'){
$d['type'] = 'purchase';
}
if($notification->type === 'App\Notifications\RemoveFeed'){
$d['type'] = 'remove-feed';
}
if($notification->type === 'App\Notifications\BannedMessageFeed'){
$d['type'] = 'banned-message-feed';
}
$user_who = User::find($data['user_id']);
if(empty($user_who)){
$notification->delete();
continue;
}
$d['user'] = [
'id' => $user_who->id,
'name' => $user_who->name,
'username' => $user_who->username,
'photo_path' => $user_who->photo_path,
'color' => $user_who->color,
'user_char' => $user_who->user_char,
];
if(@$data['node_id']){
$feed = new FeedQueryBuilder;
$d['feed'] = $feed->selectByIds($data['node_id'])->disableActiveFeed()->withTrashed()->transformGet()->first();
}else{
$d['feed'] = '';
}
$d['data'] = $data;
$d['id'] = $notification->id;
$d['created_at'] = $notification->created_at->diffForHumans();
}
$notifications_transform[] = $d;
}
return Inertia::render('Settings/SettingsNotify', [
'notifications' => $notifications_transform,
]);
}
public function money()
{
$user = auth()->user();
$points = $user
->points()
->orderBy('id', 'desc')
->cursorPaginate(User::PAGINATE);
$nextCursor = get_cursor_hash($points);
$points->each(function($line){
$dt = explode(' ', $line->created_at);
$line->date = $dt[0];
$line->time = $dt[1];
return $line;
});
if(request()->wantsJson()){
return ['collections' => $points->items(), 'next' => $nextCursor];
}
return Inertia::render('Settings/SettingsMoney', [
'points' => $points->items(),
'nextCursor' => $nextCursor,
]);
}
public function tarif()
{
$user = auth()->user();
$is_active = SubscriptionService::activeSubscription();
$user_id = $user->id;
$user_autosubscription = $user->autosubscription_site;
$plans = Package::all();
$lastSubscription = $user->subscription->first();
if ($lastSubscription) {
$lastSubscription->setRelation('package', $plans->where('id', $lastSubscription->package_id)->first());
$lastSubscription->endDateTime = $lastSubscription->ends_at->format('Y-m-d');
}
return Inertia::render('Settings/SettingsTarif', [
'plans' => $plans,
'is_active_sub' => $is_active,
'user_autosubscription' => $user_autosubscription,
'user_id' => $user_id,
'lastSubscription' => $lastSubscription,
]);
}
public function likes()
{
$feeds = (new FeedQueryBuilder(auth()->user()->likes()))->order()->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
return Inertia::render('Settings/SettingsLikes', [
'feeds' => $feeds,
'nextCursor' => $nextCursor,
]);
}
public function payouts()
{
$user = auth()->user();
// $requisites = [];
// $bankRequisites = $user->bank_requisites->first();
// if($bankRequisites){
// $requisites['id'] = $bankRequisites->id;
// $requisites['number'] = $bankRequisites->number;
// }
$withdrawals = $user->withdrawals()
->orderBy('id', 'desc')
->cursorPaginate(User::PAGINATE);
$nextCursor = get_cursor_hash($withdrawals);
$statusCode = [
'pending' => 'Запрос отправлен',
'success' => 'Запрос выполнен',
'cancel' => 'Отмена выплаты',
];
$withdrawals->each(function($line) use($statusCode) {
$dt = explode(' ', $line->created_at);
$line->datePart = $dt[0];
$line->timePart = $dt[1];
$line->meta = 'Статус: ' . $statusCode[$line->status];
$line->history_payment_details = nl2br($line->history_payment_details);
return $line;
});
if(request()->wantsJson()){
return ['collections' => $withdrawals->items(), 'next' => $nextCursor];
}
return Inertia::render('Settings/SettingsPayouts', [
// 'requisites' => $requisites,
'isVerified' => $user->isVerified(),
'withdrawals' => $withdrawals->items()
]);
}
public function packet()
{
$user = auth()->user();
$userPackage = $user->customPackage;
$purchased_subscriptions_by_users = \DB::table('users_package_customers')
->where('user_id', auth()->user()->id)->orderBy('customer_id')->orderBy('time_end', 'desc')->get();
$purchased_subscriptions_by_users = $purchased_subscriptions_by_users->groupBy('customer_id');
$subscriptions_by_users = \DB::table('users_package_customers')
->join('users_subscribers', 'users_package_customers.customer_id', '=', 'users_subscribers.user_id')
->select('users_package_customers.*', 'users_subscribers.autosubscription', 'users_subscribers.user_id as usId', 'users_subscribers.subscriber_id as subsId')
->where('users_package_customers.customer_id', auth()->user()->id)
->orderBy('users_package_customers.user_id')
->orderBy('users_package_customers.time_end', 'desc')
->get();
$subscriptions_by_users = $subscriptions_by_users->filter(function ($item) {
return $item->user_id === $item->subsId && $item->customer_id === $item->usId;
});
// $subscriptions_by_users = \DB::table('users_package_customers')
// ->where('customer_id', auth()->user()->id)
// ->orderBy('user_id')
// ->orderBy('time_end', 'desc')
// ->get();
$subscriptions_by_users = $subscriptions_by_users->groupBy('user_id');
$buyers = $this->getPacketUsers($purchased_subscriptions_by_users);
$subscriptions = $this->getPacketUsers($subscriptions_by_users);
return Inertia::render('Settings/SettingsPacket', [
'user' => $user,
'packet' => $userPackage,
'buyers' => $buyers->values()->toArray(),
'subscriptions' => $subscriptions->values()->toArray(),
]);
}
protected function getPacketUsers($subscriptions)
{
$ids_customer = $subscriptions->keys();
$users_customer = User::whereIn('id', $ids_customer)->get();
return $subscriptions->map(function ($items, $id) use($users_customer) {
$new = [];
$new['active'] = false;
$new['autosubscription'] = false;
$new['user'] = $users_customer->where('id', $id)->first()
->only([
'id', 'first_name', 'last_name',
'color', 'user_char', 'username', 'photo_path'
]);
foreach($items as $item){
// dd($items);
$carbon = \Carbon\Carbon::parse($item->time_end);
$active = now() < $carbon;
if($active){
$new['active'] = $active;
}
$new['autosubscription'] = $item->autosubscription ?? false;
$new['lists'][] = ['time_end' => $carbon->format('d.m.Y'), 'price' => $item->price, 'active' => $active];
}
return $new;
});
// dd($test);
// return $subscriptions->map(function ($item) use($users_customer,$type) {
// $carbon = \Carbon\Carbon::parse($item->time_end);
// return [
// 'id' => $item->id,
// 'price' => $item->price,
// 'time_end' => $carbon->format('d.m.Y'),
// 'active' => now() < $carbon,
// 'user' => $users_customer->first(function ($value) use($item,$type) {
// return $value->id == $item->{$type};
// })->toArray()
// ];
// });
}
public function verification(HttpRequest $request)
{
$document = $request->user()->getMedia('documents');
$first_document = $document->first();
$doc_uuid = null;
if($first_document){
$doc_uuid = $first_document->uuid;
}
$user = auth()->user();
$isPhoneVerify = $user->phone_verified;
$isPassportVerified = $user->passport_verified;
if (!empty($user->phone_verify_token) && $user->phone_verify_token_expire && $user->phone_verify_token_expire->gt(now())) {
$isToken = true;
}else{
$isToken = false;
}
return Inertia::render('Settings/SettingsVerification', [
'docUuid' => $doc_uuid,
'isToken' => $isToken,
'isPhoneVerify' => $isPhoneVerify,
'isPassportVerified' => $isPassportVerified,
'phone' => $request->user()->phone,
]);
}
public function writeToUs(HttpRequest $request)
{
return Inertia::render('Settings/SettingsWriteToUs', [
]);
}
public function documentsInfo()
{
return Inertia::render('Settings/SettingsDocuments', [
]);
}
}

View File

@@ -0,0 +1,134 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use League\Glide\ServerFactory;
use App\Domain\Feeds\Models\Feed;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Contracts\Filesystem\Filesystem;
use League\Glide\Responses\LaravelResponseFactory;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class StaticController extends Controller
{
public function show(Filesystem $filesystem, Request $request, $path)
{
$server = ServerFactory::create([
'response' => new LaravelResponseFactory($request),
'source' => $filesystem->getDriver(),
'cache' => $filesystem->getDriver(),
'cache_path_prefix' => '.glide-cache',
'base_url' => 'img',
]);
$server->setPresets([
'small' => [
'w' => 200,
'h' => 200,
'fit' => 'crop',
],
'medium' => [
'w' => 500,
'h' => 500,
'fit' => 'crop',
],
'banner' => [
'w' => 500,
'fit' => 'crop',
],
'hero' => [
'w' => 1600,
'h' => 600,
'fit' => 'crop',
],
]);
return $server->getImageResponse($path, $request->all());
}
public function avatarRemove(Filesystem $filesystem)
{
$user = auth()->user();
$server = ServerFactory::create([
'source' => $filesystem->getDriver(),
'cache' => $filesystem->getDriver(),
'cache_path_prefix' => '.glide-cache',
'base_url' => 'img',
]);
Storage::disk('public')->delete($user->photo_path);
$server->deleteCache($user->photo_path);
$user->photo_path = null;
$user->save();
return Redirect::back()->with('success', 'Аватар успешно удален!');
}
public function avatar(Request $request)
{
$user = auth()->user();
request()->validate([
'avatar' => 'required|image|mimes:jpeg,jpg,png|max:1024',
]);
$path = $request->file('avatar')->store('avatars', 'public');
$user->photo_path = $path;
$user->save();
return Redirect::back()->with('success', 'Аватар успешно обновлен!');
}
public function banner(Request $request)
{
$user = auth()->user();
request()->validate([
'banner' => 'required|image|mimes:jpeg,jpg,png|max:2048',
]);
$path = $request->file('banner')->store('banners', 'public');
$user->banner_path = $path;
$user->save();
return Redirect::back()->with('success', 'Баннер успешно обновлен!');
}
public function bannerRemove(Filesystem $filesystem)
{
$user = auth()->user();
$server = ServerFactory::create([
'source' => $filesystem->getDriver(),
'cache' => $filesystem->getDriver(),
'cache_path_prefix' => '.glide-cache',
'base_url' => 'img',
]);
Storage::disk('public')->delete($user->banner_path);
$server->deleteCache($user->banner_path);
$user->banner_path = null;
$user->save();
return Redirect::back()->with('success', 'Баннер успешно удален!');
}
public function removePreview($id)
{
$media = Media::findOrFail($id);
$feed = $media->model;
if (is_a($feed, Feed::class)) {
if ($feed->user()->is(auth()->user())) {
$media->delete();
}
}
return Redirect::back()->with('success', 'Превью успешно удалено!');
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Domain\Tags\Models\Tag;
use Illuminate\Support\Facades\Request;
use Illuminate\Http\Request as HttpRequest;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
class TagController extends Controller
{
public function index($tag)
{
$tag = Tag::where('slug', $tag)->first();
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addTags([$tag->id])
->search(Request::only('search'))
->filter($filter)
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('feed.tags', $tag->slug);
return Inertia::render('Tag/Feed', [
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'tag' => $tag,
'local_route' => $route,
'nextCursor' => $nextCursor,
'active_filter' => $filter ?? 'new'
]);
}
public function listImagesTag($tag)
{
$tag = Tag::where('slug', $tag)->first();
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addTags([$tag->id])
->addType('image')
->search(Request::only('search'))
->filter($filter)
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('list.images.tag', $tag->slug);
return Inertia::render('Image/Index', [
'nextCursor' => $nextCursor,
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'tag' => $tag,
'local_route' => $route,
'active_filter' => $filter ?? 'new'
]);
}
public function listMusicsTag($tag)
{
$tag = Tag::where('slug', $tag)->first();
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addTags([$tag->id])
->addType('music')
->search(Request::only('search'))
->filter($filter)
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('list.musics.tag', $tag->slug);
return Inertia::render('Music/Feed', [
'nextCursor' => $nextCursor,
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'tag' => $tag,
'local_route' => $route,
'active_filter' => $filter ?? 'new'
]);
}
public function listVideosTag($tag)
{
$tag = Tag::where('slug', $tag)->first();
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addTags([$tag->id])
->addType('video')
->search(Request::only('search'))
->filter($filter)
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('list.videos.tag', $tag->slug);
return Inertia::render('Video/Feed', [
'nextCursor' => $nextCursor,
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'tag' => $tag,
'local_route' => $route,
'active_filter' => $filter ?? 'new'
]);
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Inertia\Inertia;
use App\Domain\Points\Models\Point;
use App\Domain\Feeds\Service\LiveFeed;
use Illuminate\Support\Facades\Request;
use App\Domain\Users\Models\UserPackage;
use Illuminate\Support\Facades\Redirect;
use App\Domain\Points\Enums\DirectionEnum;
use App\Notifications\UserCustomPaidSubscription;
use App\Domain\Subscriptions\Service\SubscriptionService;
class UserPackageController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid')->except('show');
}
public function update()
{
$id_packet = request()->post('id');
if($id_packet){
$customPackage = UserPackage::find($id_packet);
}else{
$customPackage = new UserPackage;
}
$customPackage->price = request()->post('price');
$customPackage->user_id = auth()->user()->id;
$customPackage->save();
return Redirect::back()->with('success', 'Успешно обновлено');
}
public function subs() {
$id_packet = request()->post('packet_id');
$customPackage = UserPackage::find($id_packet);
$balance = SubscriptionService::calculate(auth()->user()->id);
if ($customPackage->price > $balance) {
return Redirect::back()->with('error', 'Недостаточно средств!');
}
\DB::beginTransaction();
$userPackage = User::find($customPackage->user_id);
$check = \DB::table('users_subscribers')
->where('user_id', auth()->user()->id)
->where('subscriber_id', $customPackage->user_id)
->first();
// в буд. по рефакторить, по сути сейчас этот код выполняется один раз
// дальше пользователю нужно отписаться, и заново купить подписку!
if(empty($check)){
auth()->user()->subscribers()->toggle([$userPackage->id]);
LiveFeed::addBySub($userPackage);
}
\DB::table('users_package_customers')->insert([
'user_id' => $customPackage->user_id,
'customer_id' => auth()->user()->id,
'package_id' => $customPackage->id,
'price' => $customPackage->price,
// 'time_end' => now()->addMonths(),
'time_end' => now()->addMinutes(10),
'created_at' => now(),
]);
$point = new Point;
$point->user_id = auth()->user()->id;
$point->point = $customPackage->price;
$point->type = 'Оформлена подписка на пользователя: ' . $userPackage->name . ' (' . $userPackage->username . ')'; //YSV ENUM!
$point->direction = DirectionEnum::EXPENSE();
$point->save();
$point = new Point;
$point->user_id = $userPackage->id;
$point->point = $customPackage->price;
$point->type = 'Пользователь оформил платную подписку: ' . auth()->user()->name . ' (' . auth()->user()->username . ')'; //YSV ENUM!
$point->direction = DirectionEnum::COMING();
$point->save();
\DB::commit();
$message = [
'user_id' => auth()->user()->id,
'node_id' => null,
];
$userPackage->notify(new UserCustomPaidSubscription($message));
return Redirect::back()->with('success', 'Подписка на пользователя успешно оформлена');
}
}

View File

@@ -0,0 +1,494 @@
<?php
namespace App\Http\Controllers;
use DB;
use Hash;
use Carbon\Carbon;
use App\Models\User;
use Inertia\Inertia;
use Illuminate\Support\Str;
use App\Domain\Tags\Models\Tag;
use Illuminate\Validation\Rule;
use App\Domain\Feeds\Models\Feed;
use App\Notifications\Subscribed;
use App\Domain\Points\Models\Point;
use App\Notifications\LeaderChoice;
use Illuminate\Support\Facades\App;
use App\Domain\Feeds\Service\LiveFeed;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Database\Eloquent\Builder;
use App\Domain\Points\Enums\DirectionEnum;
use App\Domain\Votes\Services\VoteService;
use Illuminate\Http\Request as HttpRequest;
use App\Domain\Subscriptions\Models\Package;
use App\Domain\Subscriptions\Models\Subscription;
use App\Domain\Users\DataTransferObjects\UserData;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use App\Domain\Subscriptions\Service\SubscriptionService;
class UsersController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid')->except('update', 'plan', 'postsCount', 'searchUserTag', 'testPaid');
}
public function index()
{
$users = User::filter(Request::only('search', 'sex'))
->where('id', '<>', auth()->user()->id)
->where('username', '<>', 'inner_systemuser_api')
->withCount(['subscriber_reverse as is_sub' => function (Builder $query) {
$query->where('user_id', auth()->user()->id);
}])
->withCasts(['is_sub' => 'boolean'])
->orderBy('id', 'desc')
->cursorPaginate(User::PAGINATE);
$nextCursor = get_cursor_hash($users);
$users->transform(function ($user) {
return array_merge([
'is_sub' => $user->is_sub,
], UserData::fromModel($user)->toArray());
});
if(request()->wantsJson()){
return ['collections' => $users->items(), 'next' => $nextCursor];
}
return Inertia::render('User/Index', [
'filters' => Request::all('search', 'sex'),
'nextCursor' => $nextCursor,
'users' => $users->items(),
'per_page' => User::PAGINATE,
]);
}
public function testing()
{
// $leaders = collect(SubscriptionService::leaders());
$vote = (object) ['procent_site' => 10, 'procent_top' => 60];
$t = (new VoteService($vote))->freeMode();
dd($t);
// $ids = $leaders->pluck('user_id');
// $users = User::whereIn('id', $ids)->get();
// $leaderUsers = $leaders->map(function($item) use($users) {
// $item->user = $users->where('id', $item->user_id)->first()->only(['id', 'first_name', 'last_name', 'username']);
// return $item;
// });
// dd($leaderUsers);
// dd(Str::uuid());
// $user = new \App\Models\User();
// $user->password = \Illuminate\Support\Facades\Hash::make('sysSDFGtemuser345345');
// $user->email = 'system@systemuser_api.com';
// $user->first_name = 'systemuser_api';
// $user->username = 'inner_systemuser_api';
// $user->save();
//dd($user);
// $needArray = [
// 1 => ['time' => true],
// 2 => ['time' => true],
// 3 => ['time' => true],
// ];
// $user = User::find(4);
// $plucks = $user->feeds()->pluck('created_at', 'id')->transform(function ($item) {
// return ['time' => $item->getTimestamp()];
// })->toArray();
// dd($plucks);
// DB::table('videos')->truncate();
// DB::table('musics')->truncate();
// DB::table('images')->truncate();
// DB::table('user_feed_purchase')->truncate();
// DB::table('users_feeds_like')->truncate();
// DB::table('points')->truncate();
// DB::table('notifications')->truncate();
// DB::table('feed_tags')->truncate();
// DB::table('feeds_comments')->truncate();
// DB::table('complaints')->truncate();
// DB::table('comments')->truncate();
// DB::table('feeds')->truncate();
//$feeds = Feed::all();
//foreach ($feeds as $feed) {
// $enity = $feed->feedable;
// $uuid = (string) Str::uuid();
// $feed->title = $enity->title;
// $feed->body = $enity->body;
// $feed->price = $enity->price;
// $feed->is_paid = $enity->is_paid;
// $feed->type = $feed->type;
// $feed->slug = $uuid . '_' . $feed->type;
// $feed->save();
// $medias = $enity->getMedia('common');
// $medias_paid = $enity->getMedia('paid');
// $medias_preview = $enity->getMedia('preview');
// foreach ($medias as $media) {
// if(file_exists($media->getPath())){
// $feed->addMedia($media->getPath())->toMediaCollection('common');
// }
// }
// foreach ($medias_paid as $media) {
// if(file_exists($media->getPath())){
// $feed->addMedia($media->getPath())->toMediaCollection('paid');
// }
// }
// foreach ($medias_preview as $media) {
// if(file_exists($media->getPath())){
// $feed->addMedia($media->getPath())->toMediaCollection('preview');
// }
// }
//}
}
public function update(User $user)
{
Request::validate([
'first_name' => ['required', 'max:80'],
'last_name' => ['required', 'max:80'],
'username' => ['required', 'max:80', Rule::unique('users')->ignore($user->id)],
'email' => ['required', 'max:50', 'email', Rule::unique('users')->ignore($user->id)],
'password' => ['nullable'],
'phone' => ['nullable'],
'date_of_birth' => ['nullable'],
'sex' => ['nullable'],
'type' => ['nullable'],
'private' => ['nullable'],
'inn' => ['nullable'],
'checking_account' => ['nullable'],
'bik' => ['nullable'],
// 'allow_adult_content' => ['nullable'],
'about' => ['nullable', 'max:180'],
]);
$user->update(Request::only('first_name', 'last_name', 'email', 'username', 'phone', 'date_of_birth', 'sex', 'about', 'private', 'inn', 'checking_account', 'bik', 'type'));
if (Request::get('password')) {
$user->update(['password' => Request::get('password')]);
}
return Redirect::back()->with('success', 'Профиль обновлен!');
}
public function destroy(User $user)
{
if (App::environment('demo') && $user->isDemoUser()) {
return Redirect::back()->with('error', 'Deleting the demo user is not allowed.');
}
$user->delete();
return Redirect::back()->with('success', 'User deleted.');
}
public function restore(User $user)
{
$user->restore();
return Redirect::back()->with('success', 'User restored.');
}
public function subs(User $user)
{
if($user->private){
return Redirect::back()->with('error', 'Закрытый аккаунт');
}
$check = \DB::table('users_subscribers')
->where('user_id', auth()->user()->id)
->where('subscriber_id', $user->id)
->first();
auth()->user()->subscribers()->toggle([$user->id]);
if(!$check){
$message = [
'user_id' => auth()->user()->id,
'node_id' => null,
];
$user->notify(new Subscribed($message));
LiveFeed::addBySub($user);
}else{
LiveFeed::removeBySub($user);
}
return Redirect::back()->with('success', 'Success');
}
public function removePaidSubs(User $user)
{
auth()->user()->subscribers()->toggle([$user->id]);
DB::table('users_package_customers')
->where('user_id', $user->id)
->where('customer_id', auth()->user()->id)
->delete();
LiveFeed::removeBySub($user);
return Redirect::back()->with('success', 'Успешно отписались от пользователя');
}
public function settingsAutoSubsPaidUser(User $user)
{
DB::table('users_subscribers')
->where('user_id', auth()->user()->id)
->where('subscriber_id', $user->id)
->update(['autosubscription' => DB::raw('NOT autosubscription')]);
return Redirect::back()->with('success', 'Успешно выполнено');
}
public function settingsAutoSubs(User $user)
{
$auto = $user->autosubscription_site;
if($auto){
$msg = 'Автоматическое списание отключено!';
$user->autosubscription_site = false;
}else{
$msg = 'Автоматическое списание включено!';
$user->autosubscription_site = true;
}
$user->save();
return Redirect::back()->with('success', $msg);
}
public function vote(User $user, HttpRequest $request)
{
$authUserActiveSubscription = nova_get_setting('vote_paid_mode') ? SubscriptionService::activeSubscription() : true;
if(!$authUserActiveSubscription){
return Redirect::back()->with('error', 'Только пользователи с подпиской могут выбрать лидера!');
}
$count_leader = nova_get_setting('vote_leader_count');
if(!$request->vote && auth()->user()->subscribers()->where('leader', 1)->count() >= $count_leader){
return Redirect::back()->with('error', "Можно выбрать {$count_leader} лидеров");
}
if(!$request->vote){
$message = [
'user_id' => auth()->user()->id,
'node_id' => null,
];
$user->notify(new LeaderChoice($message));
}
auth()->user()->subscribers()->updateExistingPivot($user->id, [
'leader' => ! $request->vote,
]);
return Redirect::back()->with('success', 'Success Vote!');
}
public function plan($plan_id)
{
$user = auth()->user();
$active_subscription = SubscriptionService::activeSubscription();
if ($active_subscription) {
return Redirect::back()->with('error', 'Подписка уже активирована');
}
$balance = SubscriptionService::calculate($user->id);
$plan = Package::findOrFail($plan_id);
$plan_type = $plan->type;
if ($plan_type === 'month3') {
$ends_at = Carbon::now()->addMonths(3);
} else {
$ends_at = Carbon::now()->addMonths();
}
$price = $plan->price;
if ($price > $balance) {
return Redirect::back()->with('error', 'Недостаточно средств!');
}
$sub = new Subscription;
$sub->user_id = $user->id;
$sub->package_id = $plan->id;
$sub->price = $price;
$sub->ends_at = $ends_at;
$sub->status = 'complete'; //YSV ENUM!
$sub->save();
$point = new Point;
$point->user_id = $user->id;
$point->point = $price;
$point->type = 'Оплата за подписку'; //YSV ENUM!
$point->direction = DirectionEnum::EXPENSE();
$point->save();
return Redirect::back()->with('success', 'Вы успешо подписались!');
}
public function testPaid()
{
// $price = 50;
// $user = auth()->user();
// $point = new Point;
// $point->user_id = $user->id;
// $point->point = $price;
// $point->type = 'Пополнение баланса по кнопки'; //YSV ENUM!
// $point->direction = DirectionEnum::COMING();
// $point->save();
// return Redirect::back()->with('success', 'Баланс успешно пополнен!');
}
public function postsCount($user_id)
{
$user = User::findOrFail($user_id);
return $user->feeds()->count();
}
public function searchUserTag()
{
$search = Request::input('search');
if(empty($search)){
return [
'users' => [],
'tags' => [],
];
}
$sanitize_search = Str::slug($search);
$users = User::where('username', '%'.$search.'%')
->where('username', '<>', 'inner_systemuser_api')
->orWhere('first_name', 'ilike', '%'.$search.'%')
->orWhere('last_name', 'ilike', '%'.$search.'%')->get();
$users->each(function ($item) {
$item->name = $item->name;
return $item;
});
$sanitize_search = '%'.$sanitize_search.'%';
$tags = Tag::where('slug', 'ilike', $sanitize_search)->withCount('feeds')->get();
return [
'users' => $users,
'tags' => $tags,
];
}
public function friend() {
$user = auth()->user();
$readers = $user->subscribers()->filter(Request::only('search'))
->orderBy('id', 'desc')
->cursorPaginate(50);
$users = [];
$nextCursor = get_cursor_hash($readers);
$readers->each(function ($item) use(&$users) {
$users[] = UserData::fromModel($item)->toArray();
});
return ['records' => $users, 'cursor' => $nextCursor];
}
public function updatePassword(HttpRequest $request)
{
# Validation
$request->validate([
'old_password' => 'required',
'new_password' => 'required|string|min:6',
]);
#Match The Old Password
if(!Hash::check($request->old_password, auth()->user()->password)){
return back()->with("error", "Old Password Doesn't match!");
}
#Update the new Password
User::whereId(auth()->user()->id)->update([
'password' => Hash::make($request->new_password)
]);
return back()->with("success", "Password changed successfully!");
}
public function addDocument(HttpRequest $request)
{
$this->validate($request, [
'docs' => 'required|file|image',
]);
$documents = $request->user()->getMedia('documents');
if($documents->count()){
foreach ($documents as $document) {
$document->delete();
}
}
$file = $request->file('docs');
auth()->user()->addMedia($file)->toMediaCollection('documents', 'local');
return back()->with("success", "Документ успешно загружен");
}
public function readDocument(string $uuid)
{
$media = Media::where('uuid', $uuid)->first();
return response()->download($media->getPath(), $media->file_name);
}
public function verifyPhoneRequest(Carbon $now)
{
$user = auth()->user();
if(empty($user->phone)){
return back()->with("error", "Нужно ввести телефон");
}
if (!empty($user->phone_verify_token) && $user->phone_verify_token_expire && $user->phone_verify_token_expire->gt($now)) {
return back()->with("error", "Токен уже запрошен.");
}
$user->phone_verified = false;
$user->phone_verify_token = (string)random_int(10000, 99999);
$user->phone_verify_token_expire = $now->copy()->addSeconds(300);
$user->saveOrFail();
return back()->with("success", "Верификация номера телефона успешно запрошена, ожидайте");
}
public function verifyPhone(HttpRequest $request, Carbon $now)
{
$user = auth()->user();
$token = $request->input('token');
if ($token !== $user->phone_verify_token) {
return back()->with("error", "Токен уже запрошен.");
}
if ($user->phone_verify_token_expire->lt($now)) {
return back()->with("error", "Срок действия токена истек.");
}
$user->phone_verified = true;
$user->phone_verify_token = null;
$user->phone_verify_token_expire = null;
$user->saveOrFail();
return back()->with("success", "Верификация номера телефона успешно завершена");
}
}

View File

@@ -0,0 +1,172 @@
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Domain\Feeds\Models\Feed;
use App\Domain\Feeds\Enums\StatusEnum;
use App\Http\Requests\VideoFormRequest;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Redirect;
use App\Domain\Tags\Action\CreateTagAction;
use App\Domain\Feeds\Action\CreateFeedAction;
use App\Domain\Feeds\Queries\FeedQueryBuilder;
use App\Domain\Videos\Action\CreateVideoAction;
use App\Domain\Videos\Action\UpdateVideoAction;
use App\Domain\Feeds\Service\FeedMediaTransform;
use App\Domain\Videos\DataTransferObjects\VideoData;
class VideosController extends Controller
{
public function __construct()
{
$this->middleware('subs.paid')->except('show');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$filter = Request::get('filter');
$feeds = (new FeedQueryBuilder())
->addType('video')
->search(Request::only('search'))
->filter($filter)
->enableAdvertising()
->build();
$nextCursor = $feeds->nextCursor;
$feeds = $feeds->transformData();
if(request()->wantsJson()){
return ['collections' => $feeds, 'next' => $nextCursor];
}
$route = route('videos.index');
return Inertia::render('Video/Feed', [
'nextCursor' => $nextCursor,
'searchFilters' => Request::all('search'),
'feeds' => $feeds,
'local_route' => $route,
'active_filter' => $filter ?? 'new'
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return Inertia::render('Video/Create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(VideoFormRequest $request)
{
$action = new CreateFeedAction(
new CreateVideoAction(),
new CreateTagAction(),
);
$videoData = VideoData::fromRequest($request);
$action($videoData);
$msg = 'Видео успешно загружено и находится на модерации!';
return Redirect::route('profile.user', auth()->user()->username)->with('success', $msg);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($slug)
{
$feed = new FeedQueryBuilder();
$feed = $feed->selectBy('slug', $slug)->disablePaginate()->transformGet()->first();
if(!$feed){
abort(404);
}
return Inertia::render('Video/Show', [
'user' => $feed['user'],
'feed' => $feed,
]);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($slug)
{
$feed = Feed::where('slug', $slug)->firstOrFail();
if (!$feed->user()->is(auth()->user())) {
abort(404);
}
$tags = $feed->tags()->pluck('name')->toArray();
$mediaTransform = (new FeedMediaTransform($feed))->default();
$mediaPreview = $mediaTransform->getPreviewObject();
$mediaTransformCommon = $mediaTransform->spot();
$mediaTransformPaid = (new FeedMediaTransform($feed))->paid()->spot();
return Inertia::render('Video/Edit', [
'feed' => $feed,
'tags' => $tags,
'mediaPreview' => $mediaPreview,
'mediasCount' => count($mediaTransformCommon['medias']),
'mediasCommon' => $mediaTransformCommon['medias'],
'mediasPaid' => $mediaTransformPaid['medias'],
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(VideoFormRequest $request, Feed $feed)
{
$oldStatus = $feed->status;
if (!$feed->user()->is(auth()->user())) {
abort(404);
}
$action = new CreateFeedAction(
new UpdateVideoAction($feed),
new CreateTagAction(),
);
$videoData = VideoData::fromRequest($request);
$action($videoData);
$newStatus = $feed->status;
$message = 'Видео успешно обновлено!';
if($oldStatus === StatusEnum::APPROVED() && $newStatus === StatusEnum::EDITABLE()){
$message = 'Видео успешно обновлено и находится на модерации!';
}
return Redirect::back()->with('success', $message);
}
}

71
app/Http/Kernel.php Executable file
View File

@@ -0,0 +1,71 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
// \App\Http\Middleware\EnsureEmailIsVerified::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\HandleInertiaRequests::class,
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'remember' => \Reinink\RememberQueryStrings::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'subs.paid' => \App\Http\Middleware\CheckSubscribeUser::class,
];
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\URL;
class CheckSubscribeUser
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if (! $request->user() ||
($request->user() instanceof MustVerifyEmail &&
! $request->user()->hasVerifiedEmail())) {
return $request->expectsJson()
? abort(403, 'Ваш адрес электронной почты не подтвержден.')
: Redirect::guest(URL::route('verification.notice'));
}
// if($request->path() === '/' && empty(auth()->user())){
// return $next($request);
// }
// abort_if(empty(auth()->user()), 403);
// if (auth()->user()->checkClosedAccess()) {
// return redirect(route('setting.tarif'))->with('error', 'Оплатите подписку!');
// }
return $next($request);
}
}

Some files were not shown because too many files have changed in this diff Show More