You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
493 lines
15 KiB
493 lines
15 KiB
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Models\File;
|
|
use App\Models\Model;
|
|
use App\Models\SoftDeletes;
|
|
use App\Notifications\SocketNotification;
|
|
use Illuminate\Support\Facades\Notification;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Spatie\MediaLibrary\HasMedia;
|
|
use App\Models\ReportableRelation;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
|
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
|
|
|
class Business extends Model implements HasMedia
|
|
{
|
|
use SoftDeletes,
|
|
InteractsWithMedia;
|
|
|
|
|
|
const CONVERSION_NAME = 'avatar';
|
|
|
|
const COLLECTION_NAME = 'avatars';
|
|
|
|
public static $permissions = ['level'];
|
|
|
|
protected $table = 'businesses';
|
|
|
|
protected $fillable = ['name', 'slug', 'wallet','files_volume','cache', 'color', 'description', 'has_avatar', 'calculated_at', 'suspended_at', 'users'];
|
|
|
|
protected $fillable_relations = [
|
|
'users'
|
|
];
|
|
|
|
protected $reportable = [
|
|
'name', 'slug', 'wallet', 'files_volume', 'cache', 'calculated_at', // fields
|
|
['users' => 'business_user'] // relations [ name => pivot ]
|
|
];
|
|
|
|
public $detach_relation = false;
|
|
|
|
protected $casts = [
|
|
'has_avatar' => 'boolean',
|
|
'calculated_at' => 'datetime',
|
|
'suspended_at' => 'datetime',
|
|
'wallet' => 'integer',
|
|
];
|
|
|
|
public function getValueOf(?string $key)
|
|
{
|
|
$values = [
|
|
'business_id' => $this->id,
|
|
'workflow_id' => null,
|
|
'project_id' => null,
|
|
'sprint_id' => null,
|
|
'status_id' => null,
|
|
'system_id' => null,
|
|
'user_id' => null,
|
|
'task_id' => null,
|
|
'subject_id' => $this->id,
|
|
];
|
|
|
|
if ($key && isset($values, $key)) {
|
|
return $values[$key];
|
|
}
|
|
|
|
return $values;
|
|
}
|
|
|
|
public function rules()
|
|
{
|
|
return [
|
|
'name' => 'bail|required|string|min:2|max:255',
|
|
'color' => 'nullable|string|min:2|max:255',
|
|
'slug' => ['bail', 'required', 'string', 'min:2', 'max:255', 'regex:/^[a-zA-Z]+[a-zA-Z\d-]*(.*[a-zA-Z\d])+$/',
|
|
Rule::unique($this->table, 'slug')->ignore($this->id)],
|
|
'description' => 'nullable|string|min:2|max:1000',
|
|
];
|
|
}
|
|
|
|
public function cost()
|
|
{
|
|
return $this->hasMany(Cost::class, 'business_id','id');
|
|
}
|
|
|
|
public function owners()
|
|
{
|
|
return $this->users()->wherePivot('level', '=', enum('levels.owner.id'));
|
|
}
|
|
|
|
public function members()
|
|
{
|
|
return $this->users()->wherePivot('owner', '!=', enum('levels.owner.id'));
|
|
}
|
|
|
|
public function users()
|
|
{
|
|
return $this->belongsToMany(
|
|
User::class, 'business_user', 'business_id', 'user_id',
|
|
'id', 'id', __FUNCTION__
|
|
)
|
|
->using(ReportableRelation::class)
|
|
->withPivot(self::$permissions);
|
|
}
|
|
|
|
public function tags()
|
|
{
|
|
return $this->hasMany(Tag::class, 'business_id', 'id');
|
|
}
|
|
|
|
public function projects()
|
|
{
|
|
return $this->hasMany(Project::class, 'business_id', 'id');
|
|
}
|
|
|
|
public function systems()
|
|
{
|
|
return $this->hasMany(System::class, 'business_id', 'id');
|
|
}
|
|
|
|
public function workflows()
|
|
{
|
|
return $this->hasMany(Workflow::class, 'business_id', 'id');
|
|
}
|
|
public function sprints()
|
|
{
|
|
return $this->hasMany(Sprint::class, 'business_id', 'id');
|
|
}
|
|
|
|
public function statuses()
|
|
{
|
|
return $this->hasMany(Status::class, 'business_id', 'id');
|
|
}
|
|
|
|
public function files()
|
|
{
|
|
return $this->hasMany(File::class, 'user_id', 'id');
|
|
}
|
|
|
|
public function transactions()
|
|
{
|
|
return $this->hasMany(Transaction::class, 'business_id', 'id');
|
|
}
|
|
|
|
public function updateRelations()
|
|
{
|
|
// users relations
|
|
if (!empty($this->filled_relations['users']) || $this->detach_relation) {
|
|
$this->dirties['users'] = $this->users()->sync($this->filled_relations['users'], $this->detach_relation);
|
|
}
|
|
}
|
|
|
|
|
|
public static function info($businessId, $fresh = false)
|
|
{
|
|
|
|
$info = [];
|
|
|
|
$fresh = true;
|
|
if ($fresh){
|
|
Cache::forget('business_info'.$businessId);
|
|
}
|
|
|
|
if (Cache::has('business_info'.$businessId)) {
|
|
return Cache::get('business_info'.$businessId);
|
|
} else {
|
|
$business = self::findOrFail($businessId);
|
|
|
|
$tags = $business->tags()->select('id', 'label', 'color')->get()->keyBy('id');
|
|
$info['tags'] = $tags->pluck('id');
|
|
|
|
$workflows = $business->workflows()->select ('id', 'business_id', 'name','desc')->get()->keyBy('id')
|
|
->load(['statuses'=> fn($q) => $q->select('id', 'business_id', 'workflow_id', 'name', 'state', 'order')])
|
|
->map(fn($q) => [
|
|
'id' => $q->id,
|
|
'business_id' => $q->business_id,
|
|
'name' => $q->name,
|
|
'desc' => $q->desc,
|
|
'statuses' => $q['statuses']->keyBy('id'),
|
|
]);
|
|
|
|
$info['workflows'] = $workflows->map(fn($q) => ['statuses' => $q['statuses']->pluck('id')]);
|
|
|
|
|
|
$users = $business->users()->select('id', 'name', 'email', 'mobile', 'username')->with('media')->get()
|
|
->keyBy('id')
|
|
->map(fn($u) => [
|
|
'id' => $u->id,
|
|
'name' => $u->name,
|
|
'email' => $u->email,
|
|
'mobile' => $u->mobile,
|
|
'username' => $u->get,
|
|
'avatar' => $u->has_avatar,
|
|
'level' => $u->pivot['level'],
|
|
]);
|
|
|
|
$info['users'] = $users->map(fn($u) => [
|
|
'level' => $u['level']
|
|
]);
|
|
|
|
$projects = $business->projects()->get()->keyBy('id')->load([
|
|
'members' => fn($q) => $q->select('id', 'level'),
|
|
'systems' => fn($q) => $q->select('id', 'project_id', 'name'),
|
|
'sprints' => fn($q) => $q->select('id', 'project_id', 'name', 'description', 'started_at', 'ended_at', 'active'),
|
|
'media',
|
|
]);
|
|
|
|
$info['projects'] = $projects->map(function($q) use($users){
|
|
return [
|
|
'avatar' => $q->has_avatar,
|
|
'systems' => $q->systems->pluck('id'),
|
|
'sprints' => $q->sprints->pluck('id'),
|
|
'members' => $users->keyBy('id')->map(function($u, $uid) use ($q){
|
|
$project_user = $q->members->firstWhere('id', $uid);
|
|
return $project_user? ['level' => $project_user->pivot->level, 'is_direct' => true]:
|
|
['level' => $q->private && $u['level'] != enum('levels.owner.id') ? enum('levels.inactive.id') : $u['level'],
|
|
'is_direct'=> $project_user ? true : false];
|
|
})
|
|
];
|
|
});
|
|
|
|
$business_info = array_merge(
|
|
$business->only('id', 'name', 'slug', 'color','wallet', 'files_volume'),
|
|
['avatar' => $business->has_avatar],
|
|
compact(
|
|
'info',
|
|
'tags',
|
|
'workflows',
|
|
'users',
|
|
'projects'
|
|
)
|
|
);
|
|
|
|
Cache::put('business_info'.$businessId , $business_info, config('app.cache_ttl'));
|
|
|
|
Notification::send(auth()->user(), new SocketNotification(['message' => 'business info update','payload'=>$business_info]));
|
|
|
|
return $business_info;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public static function stats()
|
|
{
|
|
return [
|
|
'users' => [
|
|
10 => [
|
|
'statuses' => [
|
|
10 => 20,
|
|
30 => 40
|
|
],
|
|
'workflows' => [
|
|
10 => 20,
|
|
30 => 40
|
|
],
|
|
'tags' => [
|
|
10 => 20,
|
|
30 => 40
|
|
],
|
|
'project' => [
|
|
10 => 20,
|
|
30 => 40
|
|
],
|
|
|
|
'sprints' => [
|
|
10 => 20,
|
|
30 => 40
|
|
],
|
|
'works' => [
|
|
],
|
|
'__subsystems' => [
|
|
10 => 20,
|
|
30 => 40
|
|
],
|
|
]
|
|
],
|
|
'workflows' => [
|
|
50 => [
|
|
'statuses' => [
|
|
20 => 50
|
|
],
|
|
|
|
]
|
|
],
|
|
'statuses' => [
|
|
10 => [
|
|
'users' => [
|
|
|
|
],
|
|
'projects' => [
|
|
|
|
]
|
|
]
|
|
],
|
|
'sprints' => [
|
|
10 => [
|
|
'statuses' => [
|
|
10 => [
|
|
10 => 1
|
|
]
|
|
]
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
public function reportActivity()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
public static function nuxtInfo($businessId)
|
|
{
|
|
if (empty($businessId)){
|
|
return null;
|
|
}
|
|
|
|
Cache::forget('business_nuxt_info' . $businessId);
|
|
return Cache::rememberForever('business_nuxt_info' . $businessId, function () use ($businessId) {
|
|
|
|
$business = self::with([
|
|
'projects.members' => fn($q) => $q->select('id', 'name'),
|
|
'projects',
|
|
'tags',
|
|
'workflows.statuses',
|
|
'workflows',
|
|
'statuses',
|
|
'users',
|
|
])->findOrFail($businessId);
|
|
|
|
|
|
$globals = [];
|
|
$business->users->each(function ($u) use (&$globals) {
|
|
$globals[$u->id] = $u->pivot->owner == true ? ['owner' => true] : $u->pivot->only(self::$permissions);
|
|
});
|
|
|
|
|
|
$projects = [];
|
|
$business->projects->each(function ($p) use (&$projects, &$globals) {
|
|
|
|
});
|
|
|
|
|
|
$business->setRelation('projects', collect($projects));
|
|
$business->setRelation('users', collect($globals));
|
|
|
|
return $business;
|
|
});
|
|
|
|
}
|
|
|
|
|
|
public static function infoOld($businessId)
|
|
{
|
|
|
|
if (empty($businessId))
|
|
return null;
|
|
|
|
|
|
Cache::forget('business_info' . $businessId);
|
|
return Cache::rememberForever('business_info' . $businessId, function () use ($businessId) {
|
|
$ob = [];
|
|
$business = self::with([
|
|
'projects.members' => fn($q) => $q->select('id', 'name'),
|
|
'projects' => fn($q) => $q->select('id', 'business_id', 'private'),
|
|
'tags' => fn($q) => $q->select('id', 'business_id', 'label'),
|
|
'sprints' => fn($q) => $q->select('id','business_id','name', 'active'),
|
|
'workflows.statuses' => fn($q) => $q->select('id', 'name'),
|
|
'workflows' => fn($q) => $q->select('id', 'business_id', 'name'),
|
|
'statuses' => fn($q) => $q->select('id', 'business_id', 'name', 'state'),
|
|
'users' => fn($q) => $q->select('id', 'name'),
|
|
])->findOrFail($businessId);
|
|
|
|
|
|
// permissions in business
|
|
$permissions = [];
|
|
$business->users->each(function ($user) use (&$permissions) {
|
|
$permissions[$user->id] = $user->pivot->only(['owner']);
|
|
$permissions[$user->id]['global_PA'] = $permissions[$user->id]['owner'] == true ?
|
|
enum('roles.manager.id') : $user->pivot->PA;
|
|
$permissions[$user->id]['global_FA'] = $permissions[$user->id]['owner'] == true ?
|
|
enum('roles.manager.id') : $user->pivot->FA;
|
|
$permissions[$user->id]['PA'] = [];
|
|
$permissions[$user->id]['FA'] = [];
|
|
});
|
|
|
|
|
|
//projects
|
|
$projects = [];
|
|
$business->projects->each(function ($p) use (&$permissions, $business, &$projects) {
|
|
|
|
$business->users->each(function ($user) use (&$permissions, $p) {
|
|
$PA = null;
|
|
$FA = null;
|
|
|
|
if ($permissions[$user->id]['owner'] == true) {
|
|
$PA = enum('roles.manager.id');
|
|
$FA = enum('roles.manager.id');
|
|
} else if (!empty($project_user = $p->getPermissions($user->id))) {
|
|
$PA = $project_user->pivot->PA;
|
|
$FA = $project_user->pivot->FA;
|
|
} else if (empty($p->getPermissions($user->id))) {
|
|
$PA = $p->private == false ? $permissions[$user->id]['global_PA'] : enum('roles.hidden.id') ;
|
|
$FA = $p->private == false ? $permissions[$user->id]['global_FA'] : enum('roles.hidden.id');
|
|
}
|
|
|
|
|
|
if ($PA !== null && $FA !== null) {
|
|
$permissions[$user->id]['PA'][$p->id] = $PA;
|
|
$permissions[$user->id]['FA'][$p->id] = $FA;
|
|
}
|
|
});
|
|
|
|
$projects[$p->id] ='';
|
|
});
|
|
|
|
|
|
//workflow
|
|
$workflows = [];
|
|
$business->workflows->each(function ($w) use (&$workflows) {
|
|
$workflows[$w->id] = $w->statuses->pluck('id');
|
|
});
|
|
|
|
|
|
$ob['tags'] = $business->tags->pluck('id');
|
|
$ob['statuses'] = $business->statuses;
|
|
$ob['sprints'] = $business->sprints;
|
|
$ob['workflows'] = $workflows;
|
|
$ob['users'] = $permissions;
|
|
$ob['projects'] = $projects;
|
|
|
|
return collect($ob);
|
|
});
|
|
|
|
}
|
|
|
|
public function registerMediaCollections(): void
|
|
{
|
|
$this->addMediaCollection(static::COLLECTION_NAME)
|
|
->acceptsMimeTypes([
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/tiff',
|
|
'image/gif',
|
|
])
|
|
->useDisk('public')
|
|
->singleFile();
|
|
}
|
|
|
|
public function registerMediaConversions(Media $media = null): void
|
|
{
|
|
$this->addMediaConversion(static::CONVERSION_NAME)
|
|
->width(200)
|
|
->height(200)
|
|
->queued()
|
|
->nonOptimized()
|
|
->performOnCollections(static::COLLECTION_NAME);
|
|
}
|
|
|
|
|
|
public function saveAsAvatar(UploadedFile $avatar): void
|
|
{
|
|
$this->addMedia($avatar)->toMediaCollection(static::COLLECTION_NAME);
|
|
$this->update([
|
|
'has_avatar' => true,
|
|
]);
|
|
@unlink($this->getFirstMedia(static::COLLECTION_NAME)->getPath());
|
|
}
|
|
|
|
public function deleteAvatar(): void
|
|
{
|
|
$path = $this->getFirstMedia(static::COLLECTION_NAME)->getPath();
|
|
$this->getFirstMedia(static::COLLECTION_NAME)->delete();
|
|
$this->update([
|
|
'has_avatar' => false,
|
|
]);
|
|
@unlink($path);
|
|
}
|
|
|
|
public function getAvatarUrl(): ?string
|
|
{
|
|
if ($url = $this->getFirstMediaUrl(static::COLLECTION_NAME, static::CONVERSION_NAME)) {
|
|
return $url;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|