mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-12-20 12:03:16 +00:00
Merge pull request #503 from pixelfed/frontend-ui-refactor
Frontend ui refactor
This commit is contained in:
commit
c8ff9194c5
24 changed files with 378 additions and 49 deletions
|
@ -21,6 +21,12 @@ class Follower extends Model
|
|||
return $this->belongsTo(Profile::class, 'following_id', 'id');
|
||||
}
|
||||
|
||||
public function permalink()
|
||||
{
|
||||
$path = $this->actor->permalink("/follow/{$this->id}");
|
||||
return url($path);
|
||||
}
|
||||
|
||||
public function toText()
|
||||
{
|
||||
$actorName = $this->actor->username;
|
||||
|
|
|
@ -64,12 +64,12 @@ class AccountController extends Controller
|
|||
]);
|
||||
$profile = Auth::user()->profile;
|
||||
$action = $request->input('a');
|
||||
$timeago = Carbon::now()->subMonths(1);
|
||||
$timeago = Carbon::now()->subMonths(3);
|
||||
$following = $profile->following->pluck('id');
|
||||
$notifications = Notification::whereIn('actor_id', $following)
|
||||
->where('profile_id', '!=', $profile->id)
|
||||
->whereDate('created_at', '>', $timeago)
|
||||
->orderBy('notifications.id', 'desc')
|
||||
->orderBy('notifications.created_at', 'desc')
|
||||
->simplePaginate(30);
|
||||
|
||||
return view('account.following', compact('profile', 'notifications'));
|
||||
|
|
|
@ -22,6 +22,7 @@ class StatusController extends Controller
|
|||
$user = Profile::whereUsername($username)->firstOrFail();
|
||||
|
||||
$status = Status::whereProfileId($user->id)
|
||||
->where('visibility', '!=', 'draft')
|
||||
->withCount(['likes', 'comments', 'media'])
|
||||
->findOrFail($id);
|
||||
|
||||
|
@ -41,7 +42,7 @@ class StatusController extends Controller
|
|||
|
||||
$template = $this->detectTemplate($status);
|
||||
|
||||
$replies = Status::whereInReplyToId($status->id)->simplePaginate(30);
|
||||
$replies = Status::whereInReplyToId($status->id)->orderBy('created_at', 'desc')->simplePaginate(30);
|
||||
|
||||
return view($template, compact('user', 'status', 'replies'));
|
||||
}
|
||||
|
@ -59,6 +60,9 @@ class StatusController extends Controller
|
|||
if ($status->viewType() == 'video') {
|
||||
$template = 'status.show.video';
|
||||
}
|
||||
if ($status->viewType() == 'video-album') {
|
||||
$template = 'status.show.video-album';
|
||||
}
|
||||
|
||||
return $template;
|
||||
});
|
||||
|
@ -85,13 +89,7 @@ class StatusController extends Controller
|
|||
}
|
||||
|
||||
$this->validate($request, [
|
||||
'photo.*' => function() {
|
||||
return [
|
||||
'required',
|
||||
'mimes:' . config('pixelfed.media_types'),
|
||||
'max:' . config('pixelfed.max_photo_size'),
|
||||
];
|
||||
},
|
||||
'photo.*' => 'required|mimetypes:' . config('pixelfed.media_types').'|max:' . config('pixelfed.max_photo_size'),
|
||||
'caption' => 'string|max:'.config('pixelfed.max_caption_length'),
|
||||
'cw' => 'nullable|string',
|
||||
'filter_class' => 'nullable|string',
|
||||
|
|
|
@ -29,6 +29,7 @@ class TimelineController extends Controller
|
|||
->pluck('filterable_id');
|
||||
$timeline = Status::whereIn('profile_id', $following)
|
||||
->whereNotIn('profile_id', $filtered)
|
||||
->whereVisibility('public')
|
||||
->orderBy('created_at', 'desc')
|
||||
->withCount(['comments', 'likes'])
|
||||
->simplePaginate(20);
|
||||
|
|
|
@ -32,4 +32,32 @@ class Media extends Model
|
|||
|
||||
return url($url);
|
||||
}
|
||||
|
||||
public function mimeType()
|
||||
{
|
||||
return explode('/', $this->mime)[0];
|
||||
}
|
||||
|
||||
public function activityVerb()
|
||||
{
|
||||
$verb = 'Image';
|
||||
switch ($this->mimeType()) {
|
||||
case 'image':
|
||||
break;
|
||||
|
||||
case 'video':
|
||||
$verb = 'Video';
|
||||
break;
|
||||
|
||||
default:
|
||||
$verb = 'Document';
|
||||
break;
|
||||
}
|
||||
return $verb;
|
||||
}
|
||||
|
||||
public function getMetadata()
|
||||
{
|
||||
return json_decode($this->metadata, true, 3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class Profile extends Model
|
|||
'private_key',
|
||||
];
|
||||
|
||||
protected $visible = ['id', 'username', 'name'];
|
||||
protected $visible = ['username', 'name'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
|
@ -51,6 +51,10 @@ class Profile extends Model
|
|||
|
||||
public function emailUrl()
|
||||
{
|
||||
if($this->domain) {
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
$domain = parse_url(config('app.url'), PHP_URL_HOST);
|
||||
|
||||
return $this->username.'@'.$domain;
|
||||
|
@ -137,7 +141,7 @@ class Profile extends Model
|
|||
{
|
||||
$url = Cache::remember("avatar:{$this->id}", 1440, function () {
|
||||
$path = optional($this->avatar)->media_path;
|
||||
$version = hash('sha1', $this->avatar->created_at);
|
||||
$version = hash('sha1', $this->avatar->updated_at);
|
||||
$path = "{$path}?v={$version}";
|
||||
|
||||
return url(Storage::url($path));
|
||||
|
|
|
@ -18,6 +18,8 @@ class Status extends Model
|
|||
*/
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
protected $fillable = ['profile_id', 'visibility'];
|
||||
|
||||
public function profile()
|
||||
{
|
||||
return $this->belongsTo(Profile::class);
|
||||
|
@ -36,16 +38,21 @@ class Status extends Model
|
|||
public function viewType()
|
||||
{
|
||||
$media = $this->firstMedia();
|
||||
$type = explode('/', $media->mime);
|
||||
$mime = explode('/', $media->mime)[0];
|
||||
$count = $this->media()->count();
|
||||
$type = ($mime == 'image') ? 'image' : 'video';
|
||||
if($count > 1) {
|
||||
$type = ($type == 'image') ? 'album' : 'video-album';
|
||||
}
|
||||
|
||||
return $type[0];
|
||||
return $type;
|
||||
}
|
||||
|
||||
public function thumb($showNsfw = false)
|
||||
{
|
||||
$type = $this->viewType();
|
||||
$is_nsfw = !$showNsfw ? $this->is_nsfw : false;
|
||||
if ($this->media->count() == 0 || $is_nsfw || $type != 'image') {
|
||||
if ($this->media->count() == 0 || $is_nsfw || !in_array($type,['image', 'album'])) {
|
||||
return 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==';
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ class AccountTransformer extends Fractal\TransformerAbstract
|
|||
'url' => $profile->url(),
|
||||
'avatar' => $profile->avatarUrl(),
|
||||
'avatar_static' => $profile->avatarUrl(),
|
||||
'header' => '',
|
||||
'header_static' => '',
|
||||
'header' => null,
|
||||
'header_static' => null,
|
||||
'moved' => null,
|
||||
'fields' => null,
|
||||
'bot' => null,
|
||||
|
|
|
@ -11,7 +11,7 @@ class MediaTransformer extends Fractal\TransformerAbstract
|
|||
{
|
||||
return [
|
||||
'id' => $media->id,
|
||||
'type' => 'image',
|
||||
'type' => $media->activityVerb(),
|
||||
'url' => $media->url(),
|
||||
'remote_url' => null,
|
||||
'preview_url' => $media->thumbnailUrl(),
|
||||
|
|
|
@ -35,7 +35,8 @@ class User extends Authenticatable
|
|||
protected $hidden = [
|
||||
'email', 'password', 'is_admin', 'remember_token',
|
||||
'email_verified_at', '2fa_enabled', '2fa_secret',
|
||||
'2fa_backup_codes', '2fa_setup_at',
|
||||
'2fa_backup_codes', '2fa_setup_at', 'deleted_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
public function profile()
|
||||
|
@ -52,4 +53,9 @@ class User extends Authenticatable
|
|||
{
|
||||
return $this->hasOne(UserSetting::class);
|
||||
}
|
||||
|
||||
public function receivesBroadcastNotificationsOn()
|
||||
{
|
||||
return 'App.User.'.$this->id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ class Image
|
|||
public $portrait;
|
||||
public $thumbnail;
|
||||
public $orientation;
|
||||
public $acceptedMimes = [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -22,8 +26,8 @@ class Image
|
|||
$this->landscape = $this->orientations()['landscape'];
|
||||
$this->portrait = $this->orientations()['portrait'];
|
||||
$this->thumbnail = [
|
||||
'width' => 293,
|
||||
'height' => 293,
|
||||
'width' => 640,
|
||||
'height' => 640,
|
||||
];
|
||||
$this->orientation = null;
|
||||
}
|
||||
|
@ -98,18 +102,22 @@ class Image
|
|||
{
|
||||
$path = $media->media_path;
|
||||
$file = storage_path('app/'.$path);
|
||||
if (!in_array($media->mime, $this->acceptedMimes)) {
|
||||
return;
|
||||
}
|
||||
$ratio = $this->getAspectRatio($file, $thumbnail);
|
||||
$aspect = $ratio['dimensions'];
|
||||
$orientation = $ratio['orientation'];
|
||||
if ($media->mime === 'image/gif' && !$thumbnail) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$img = Intervention::make($file)->orientate();
|
||||
if($thumbnail) {
|
||||
$img->crop($aspect['width'], $aspect['height']);
|
||||
} else {
|
||||
$img->resize($aspect['width'], $aspect['height'], function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
});
|
||||
}
|
||||
$converted = $this->setBaseName($path, $thumbnail, $img->extension);
|
||||
$newPath = storage_path('app/'.$converted['path']);
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ return [
|
|||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'strict' => true,
|
||||
'strict' => false,
|
||||
'engine' => null,
|
||||
],
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ php artisan storage:link
|
|||
php artisan migrate --force
|
||||
|
||||
# Run a worker if it is set as embedded
|
||||
if [ HORIZON_EMBED = true ]; then
|
||||
if [ $HORIZON_EMBED = true ]; then
|
||||
php artisan horizon &
|
||||
fi
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateStoriesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('stories', function (Blueprint $table) {
|
||||
$table->increments('bigIncrements');
|
||||
$table->bigInteger('profile_id')->unsigned();
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('stories');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateStoryReactionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('story_reactions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('profile_id')->unsigned()->nullable();
|
||||
$table->string('reaction')->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('story_reactions');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCollectionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('collections', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('profile_id')->unsigned()->nullable();
|
||||
$table->string('title')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->boolean('is_nsfw')->default(false);
|
||||
$table->string('visibility')->default('public')->index();
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('collections');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateDirectMessagesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('direct_messages', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('to_id')->unsigned()->index();
|
||||
$table->bigInteger('from_id')->unsigned()->index();
|
||||
$table->string('from_profile_ids')->nullable();
|
||||
$table->boolean('group_message')->default(false);
|
||||
$table->bigInteger('status_id')->unsigned()->integer();
|
||||
$table->unique(['to_id', 'from_id', 'status_id']);
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('direct_messages');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCollectionItemsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('collection_items', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('collection_id')->unsigned()->index();
|
||||
$table->unsignedInteger('order')->nullable();
|
||||
$table->string('object_type')->default('post')->index();
|
||||
$table->bigInteger('object_id')->unsigned()->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('collection_items');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class UpdateStatusVisibilityDefaults extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::statement("ALTER TABLE statuses CHANGE COLUMN visibility visibility ENUM('public','unlisted','private','direct', 'draft') NOT NULL DEFAULT 'public'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
16
resources/lang/en/site.php
Normal file
16
resources/lang/en/site.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'about' => 'About',
|
||||
'help' => 'Help',
|
||||
'language' => 'Language',
|
||||
'fediverse' => 'Fediverse',
|
||||
'opensource' => 'Open Source',
|
||||
'terms' => 'Terms',
|
||||
'privacy' => 'Privacy',
|
||||
'l10nWip' => 'We’re still working on localization support',
|
||||
'currentLocale' => 'Current locale',
|
||||
'selectLocale' => 'Select from one of the supported languages',
|
||||
|
||||
];
|
16
resources/lang/fr/site.php
Normal file
16
resources/lang/fr/site.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'about' => 'Environ',
|
||||
'help' => 'Aidez-moi',
|
||||
'language' => 'La langue',
|
||||
'fediverse' => 'Fediverse',
|
||||
'opensource' => 'Open Source',
|
||||
'terms' => 'Termes',
|
||||
'privacy' => 'Intimité',
|
||||
'l10nWip' => 'Nous travaillons toujours sur le support de la localisation',
|
||||
'currentLocale' => 'Locale actuelle',
|
||||
'selectLocale' => 'Sélectionnez l\'une des langues prises en charge',
|
||||
|
||||
];
|
|
@ -30,30 +30,33 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@php($reports = App\Report::whereNull('admin_seen')->count())
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h2">{{App\Util\Lexer\PrettyNumber::convert(App\Report::whereNull('admin_seen')->count())}}</p>
|
||||
<p class="h2" title="{{$reports}}" data-toggle="tooltip">{{App\Util\Lexer\PrettyNumber::convert($reports)}}</p>
|
||||
<p class="small text-uppercase font-weight-bold text-muted mb-0">Reports</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php($statuses = App\Status::whereNull('in_reply_to_id')->whereNull('reblog_of_id')->count())
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h2">{{App\Util\Lexer\PrettyNumber::convert(App\Status::whereNull('in_reply_to_id')->whereNull('reblog_of_id')->count())}}</p>
|
||||
<p class="h2" title="{{$statuses}}" data-toggle="tooltip">{{App\Util\Lexer\PrettyNumber::convert($statuses)}}</p>
|
||||
<p class="small text-uppercase font-weight-bold text-muted mb-0">Statuses</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php($replies = App\Status::whereNotNull('in_reply_to_id')->count())
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h2">{{App\Util\Lexer\PrettyNumber::convert(App\Status::whereNotNull('in_reply_to_id')->count())}}</p>
|
||||
<p class="h2" title="{{$replies}}" data-toggle="tooltip">{{App\Util\Lexer\PrettyNumber::convert($replies)}}</p>
|
||||
<p class="small text-uppercase font-weight-bold text-muted mb-0">Replies</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<div class="card mx-5">
|
||||
<div class="card-body p-5 text-center">
|
||||
<h1>Whoops! Something went wrong.</h1>
|
||||
<p class="mb-0 text-muted lead">Please try again, if this error keeps happening please contact an admin.</p>
|
||||
<p class="mb-0 text-muted lead">If you keep seeing this message, please contact an admin.</p>
|
||||
<img src="/img/fred1.gif" class="img-fluid">
|
||||
</div>
|
||||
</div>
|
||||
|
|
31
tests/Feature/LoginTest.php
Normal file
31
tests/Feature/LoginTest.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
|
||||
class LoginTest extends TestCase
|
||||
{
|
||||
|
||||
/** @test */
|
||||
public function view_login_page()
|
||||
{
|
||||
$response = $this->get('login');
|
||||
|
||||
$response->assertSuccessful()
|
||||
->assertSee('Forgot Your Password?');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function view_register_page()
|
||||
{
|
||||
if(true === config('pixelfed.open_registration')) {
|
||||
$response = $this->get('register');
|
||||
|
||||
$response->assertSuccessful()
|
||||
->assertSee('Register a new account');
|
||||
} else {
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue