mirror of
https://github.com/pixelfed/pixelfed.git
synced 2025-01-03 10:50:46 +00:00
Merge pull request #354 from pixelfed/frontend-ui-refactor
Frontend ui refactor
This commit is contained in:
commit
ba39aca471
5 changed files with 221 additions and 3 deletions
|
@ -3,8 +3,91 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Auth, Log, Storage;
|
||||||
|
use App\Avatar;
|
||||||
|
use App\Jobs\AvatarPipeline\AvatarOptimize;
|
||||||
|
|
||||||
class AvatarController extends Controller
|
class AvatarController extends Controller
|
||||||
{
|
{
|
||||||
//
|
public function __construct()
|
||||||
|
{
|
||||||
|
return $this->middleware('auth');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'avatar' => 'required|mimes:jpeg,png|max:1000'
|
||||||
|
]);
|
||||||
|
try {
|
||||||
|
$user = Auth::user();
|
||||||
|
$file = $request->file('avatar');
|
||||||
|
$path = $this->getPath($user, $file);
|
||||||
|
$dir = $path['root'];
|
||||||
|
$name = $path['name'];
|
||||||
|
$public = $path['storage'];
|
||||||
|
$currentAvatar = storage_path('app/'.$user->profile->avatar->media_path);
|
||||||
|
$loc = $request->file('avatar')->storeAs($public, $name);
|
||||||
|
|
||||||
|
$avatar = Avatar::whereProfileId($user->profile->id)->firstOrFail();
|
||||||
|
$opath = $avatar->media_path;
|
||||||
|
$avatar->media_path = "$public/$name";
|
||||||
|
$avatar->thumb_path = null;
|
||||||
|
$avatar->change_count = ++$avatar->change_count;
|
||||||
|
$avatar->last_processed_at = null;
|
||||||
|
$avatar->save();
|
||||||
|
|
||||||
|
AvatarOptimize::dispatch($user->profile, $currentAvatar);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
}
|
||||||
|
return redirect()->back()->with('status', 'Avatar updated successfully. It may take a few minutes to update across the site.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPath($user, $file)
|
||||||
|
{
|
||||||
|
$basePath = storage_path('app/public/avatars');
|
||||||
|
$this->checkDir($basePath);
|
||||||
|
|
||||||
|
$id = $user->profile->id;
|
||||||
|
$path = $this->buildPath($id);
|
||||||
|
$dir = storage_path('app/'.$path);
|
||||||
|
$this->checkDir($dir);
|
||||||
|
$name = 'avatar.' . $file->guessExtension();
|
||||||
|
$res = ['root' => 'storage/app/' . $path, 'name' => $name, 'storage' => $path];
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkDir($path)
|
||||||
|
{
|
||||||
|
if(!is_dir($path)) {
|
||||||
|
mkdir($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildPath($id)
|
||||||
|
{
|
||||||
|
$padded = str_pad($id, 12, 0, STR_PAD_LEFT);
|
||||||
|
$parts = str_split($padded, 3);
|
||||||
|
foreach($parts as $k => $part) {
|
||||||
|
if($k == 0) {
|
||||||
|
$prefix = storage_path('app/public/avatars/'.$parts[0]);
|
||||||
|
$this->checkDir($prefix);
|
||||||
|
}
|
||||||
|
if($k == 1) {
|
||||||
|
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1]);
|
||||||
|
$this->checkDir($prefix);
|
||||||
|
}
|
||||||
|
if($k == 2) {
|
||||||
|
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2]);
|
||||||
|
$this->checkDir($prefix);
|
||||||
|
}
|
||||||
|
if($k == 3) {
|
||||||
|
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3];
|
||||||
|
$prefix = storage_path('app/'.$avatarpath);
|
||||||
|
$this->checkDir($prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $avatarpath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
70
app/Jobs/AvatarPipeline/AvatarOptimize.php
Normal file
70
app/Jobs/AvatarPipeline/AvatarOptimize.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\AvatarPipeline;
|
||||||
|
|
||||||
|
use \Carbon\Carbon;
|
||||||
|
use Image as Intervention;
|
||||||
|
use App\{Avatar, Profile};
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class AvatarOptimize implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $profile;
|
||||||
|
protected $current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Profile $profile, $current)
|
||||||
|
{
|
||||||
|
$this->profile = $profile;
|
||||||
|
$this->current = $current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$avatar = $this->profile->avatar;
|
||||||
|
$file = storage_path("app/$avatar->media_path");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$img = Intervention::make($file)->orientate();
|
||||||
|
$img->fit(200, 200, function ($constraint) {
|
||||||
|
$constraint->upsize();
|
||||||
|
});
|
||||||
|
$quality = config('pixelfed.image_quality');
|
||||||
|
$img->save($file, $quality);
|
||||||
|
|
||||||
|
$avatar = Avatar::whereProfileId($this->profile->id)->firstOrFail();
|
||||||
|
$avatar->thumb_path = $avatar->media_path;
|
||||||
|
$avatar->change_count = ++$avatar->change_count;
|
||||||
|
$avatar->last_processed_at = Carbon::now();
|
||||||
|
$avatar->save();
|
||||||
|
$this->deleteOldAvatar($avatar->media_path, $this->current);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function deleteOldAvatar($new, $current)
|
||||||
|
{
|
||||||
|
if(storage_path('app/' . $new) == $current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(is_file($current)) {
|
||||||
|
@unlink($current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,41 @@
|
||||||
<h3 class="font-weight-bold">Avatar Settings</h3>
|
<h3 class="font-weight-bold">Avatar Settings</h3>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="alert alert-danger">
|
<div class="row mt-3">
|
||||||
Coming Soon
|
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<p class="font-weight-bold text-center">Current Avatar</p>
|
||||||
|
<img src="{{Auth::user()->profile->avatarUrl()}}" class="img-thumbnail rounded-circle">
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-7 offset-md-1">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header font-weight-bold bg-white">Update Avatar</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-file">
|
||||||
|
<input type="file" class="custom-file-input" id="fileInput" name="avatar" accept="image/*">
|
||||||
|
<label class="custom-file-label" for="fileInput">Upload New Avatar</label>
|
||||||
|
</div>
|
||||||
|
<small class="form-text text-muted">
|
||||||
|
Max Size: 1 MB. Supported formats: jpeg, png.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mt-5 pt-5">
|
||||||
|
<hr>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-12 text-right">
|
||||||
|
{{-- <a class="btn btn-secondary font-weight-bold py-1" href="#">Restore Default Avatar</a> --}}
|
||||||
|
<button type="submit" class="btn btn-primary font-weight-bold py-1">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
|
@ -3,11 +3,42 @@
|
||||||
<li class="nav-item pl-3 {{request()->is('settings/home')?'active':''}}">
|
<li class="nav-item pl-3 {{request()->is('settings/home')?'active':''}}">
|
||||||
<a class="nav-link font-weight-light text-muted" href="{{route('settings')}}">Profile</a>
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings')}}">Profile</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item pl-3 {{request()->is('settings/avatar')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.avatar')}}">Avatar</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item pl-3 {{request()->is('settings/password')?'active':''}}">
|
<li class="nav-item pl-3 {{request()->is('settings/password')?'active':''}}">
|
||||||
<a class="nav-link font-weight-light text-muted" href="{{route('settings.password')}}">Password</a>
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.password')}}">Password</a>
|
||||||
</li>
|
</li>
|
||||||
|
{{-- <li class="nav-item pl-3 {{request()->is('settings/email')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.email')}}">Email</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item pl-3 {{request()->is('settings/notifications')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.notifications')}}">Notifications</a>
|
||||||
|
</li> --}}
|
||||||
<li class="nav-item pl-3 {{request()->is('settings/privacy')?'active':''}}">
|
<li class="nav-item pl-3 {{request()->is('settings/privacy')?'active':''}}">
|
||||||
<a class="nav-link font-weight-light text-muted" href="{{route('settings.privacy')}}">Privacy</a>
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.privacy')}}">Privacy</a>
|
||||||
</li>
|
</li>
|
||||||
|
{{-- <li class="nav-item pl-3 {{request()->is('settings/security')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.security')}}">Security</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<hr>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item pl-3 {{request()->is('settings/import*')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.import')}}">Import</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item pl-3 {{request()->is('settings/data-export')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.dataexport')}}">Export</a>
|
||||||
|
</li>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<hr>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item pl-3 {{request()->is('settings/applications')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.applications')}}">Applications</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item pl-3 {{request()->is('settings/developers')?'active':''}}">
|
||||||
|
<a class="nav-link font-weight-light text-muted" href="{{route('settings.developers')}}">Developers</a>
|
||||||
|
</li> --}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
|
@ -85,6 +85,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware('validemail')->group(fu
|
||||||
Route::get('home', 'SettingsController@home')->name('settings');
|
Route::get('home', 'SettingsController@home')->name('settings');
|
||||||
Route::post('home', 'SettingsController@homeUpdate');
|
Route::post('home', 'SettingsController@homeUpdate');
|
||||||
Route::get('avatar', 'SettingsController@avatar')->name('settings.avatar');
|
Route::get('avatar', 'SettingsController@avatar')->name('settings.avatar');
|
||||||
|
Route::post('avatar', 'AvatarController@store');
|
||||||
Route::get('password', 'SettingsController@password')->name('settings.password');
|
Route::get('password', 'SettingsController@password')->name('settings.password');
|
||||||
Route::post('password', 'SettingsController@passwordUpdate');
|
Route::post('password', 'SettingsController@passwordUpdate');
|
||||||
Route::get('email', 'SettingsController@email')->name('settings.email');
|
Route::get('email', 'SettingsController@email')->name('settings.email');
|
||||||
|
|
Loading…
Reference in a new issue