mirror of https://github.com/pixelfed/pixelfed
commit
cdb8784d81
@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use Cache, DB;
|
||||
use Illuminate\Http\Request;
|
||||
use App\ModLog;
|
||||
use App\Profile;
|
||||
use App\User;
|
||||
use App\Mail\AdminMessage;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Services\ModLogService;
|
||||
use App\Jobs\DeletePipeline\DeleteAccountPipeline;
|
||||
|
||||
trait AdminUserController
|
||||
{
|
||||
public function users(Request $request)
|
||||
{
|
||||
$col = $request->query('col') ?? 'id';
|
||||
$dir = $request->query('dir') ?? 'desc';
|
||||
$users = User::select('id', 'username', 'status')
|
||||
->withCount('statuses')
|
||||
->orderBy($col, $dir)
|
||||
->simplePaginate(10);
|
||||
|
||||
return view('admin.users.home', compact('users'));
|
||||
}
|
||||
|
||||
public function userShow(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
return view('admin.users.show', compact('user', 'profile'));
|
||||
}
|
||||
|
||||
public function userEdit(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
return view('admin.users.edit', compact('user', 'profile'));
|
||||
}
|
||||
|
||||
public function userEditSubmit(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
$changed = false;
|
||||
$fields = [];
|
||||
|
||||
if($request->filled('name') && $request->input('name') != $user->name) {
|
||||
$fields['name'] = ['old' => $user->name, 'new' => $request->input('name')];
|
||||
$user->name = $profile->name = $request->input('name');
|
||||
$changed = true;
|
||||
}
|
||||
if($request->filled('username') && $request->input('username') != $user->username) {
|
||||
$fields['username'] = ['old' => $user->username, 'new' => $request->input('username')];
|
||||
$user->username = $profile->username = $request->input('username');
|
||||
$changed = true;
|
||||
}
|
||||
if($request->filled('email') && $request->input('email') != $user->email) {
|
||||
if(filter_var($request->input('email'), FILTER_VALIDATE_EMAIL) == false) {
|
||||
abort(500, 'Invalid email address');
|
||||
}
|
||||
$fields['email'] = ['old' => $user->email, 'new' => $request->input('email')];
|
||||
$user->email = $request->input('email');
|
||||
$changed = true;
|
||||
}
|
||||
if($request->input('bio') != $profile->bio) {
|
||||
$fields['bio'] = ['old' => $user->bio, 'new' => $request->input('bio')];
|
||||
$profile->bio = $request->input('bio');
|
||||
$changed = true;
|
||||
}
|
||||
if($request->input('website') != $profile->website) {
|
||||
$fields['website'] = ['old' => $user->website, 'new' => $request->input('website')];
|
||||
$profile->website = $request->input('website');
|
||||
$changed = true;
|
||||
}
|
||||
|
||||
if($changed == true) {
|
||||
ModLogService::boot()
|
||||
->objectUid($user->id)
|
||||
->objectId($user->id)
|
||||
->objectType('App\User::class')
|
||||
->user($request->user())
|
||||
->action('admin.user.edit')
|
||||
->metadata([
|
||||
'fields' => $fields
|
||||
])
|
||||
->accessLevel('admin')
|
||||
->save();
|
||||
$profile->save();
|
||||
$user->save();
|
||||
}
|
||||
|
||||
|
||||
return redirect('/i/admin/users/show/' . $user->id);
|
||||
}
|
||||
|
||||
public function userActivity(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
$logs = $user->accountLog()->orderByDesc('created_at')->paginate(10);
|
||||
return view('admin.users.activity', compact('user', 'profile', 'logs'));
|
||||
}
|
||||
|
||||
public function userMessage(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
return view('admin.users.message', compact('user', 'profile'));
|
||||
}
|
||||
|
||||
public function userMessageSend(Request $request, $id)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'message' => 'required|string|min:5|max:500'
|
||||
]);
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
$message = $request->input('message');
|
||||
Mail::to($user->email)->send(new AdminMessage($message));
|
||||
ModLogService::boot()
|
||||
->objectUid($user->id)
|
||||
->objectId($user->id)
|
||||
->objectType('App\User::class')
|
||||
->user($request->user())
|
||||
->action('admin.user.mail')
|
||||
->metadata([
|
||||
'message' => $message
|
||||
])
|
||||
->accessLevel('admin')
|
||||
->save();
|
||||
return redirect('/i/admin/users/show/' . $user->id);
|
||||
}
|
||||
|
||||
public function userModTools(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
return view('admin.users.modtools', compact('user', 'profile'));
|
||||
}
|
||||
|
||||
public function userModLogs(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
$logs = ModLog::whereObjectUid($user->id)
|
||||
->orderByDesc('created_at')
|
||||
->simplePaginate(10);
|
||||
return view('admin.users.modlogs', compact('user', 'profile', 'logs'));
|
||||
}
|
||||
|
||||
public function userModLogsMessage(Request $request, $id)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'message' => 'required|string|min:5|max:500'
|
||||
]);
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
$msg = $request->input('message');
|
||||
ModLogService::boot()
|
||||
->objectUid($user->id)
|
||||
->objectId($user->id)
|
||||
->objectType('App\User::class')
|
||||
->user($request->user())
|
||||
->message($msg)
|
||||
->accessLevel('admin')
|
||||
->save();
|
||||
return redirect('/i/admin/users/modlogs/' . $user->id);
|
||||
}
|
||||
|
||||
public function userDelete(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
return view('admin.users.delete', compact('user', 'profile'));
|
||||
}
|
||||
|
||||
public function userDeleteProcess(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$profile = $user->profile;
|
||||
|
||||
if(config('pixelfed.account_deletion') == false) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
if($user->is_admin == true) {
|
||||
$mid = $request->user()->id;
|
||||
abort_if($user->id < $mid, 403);
|
||||
}
|
||||
|
||||
$ts = now()->addMonth();
|
||||
$user->status = 'delete';
|
||||
$profile->status = 'delete';
|
||||
$user->delete_after = $ts;
|
||||
$profile->delete_after = $ts;
|
||||
$user->save();
|
||||
$profile->save();
|
||||
|
||||
ModLogService::boot()
|
||||
->objectUid($user->id)
|
||||
->objectId($user->id)
|
||||
->objectType('App\User::class')
|
||||
->user($request->user())
|
||||
->action('admin.user.delete')
|
||||
->accessLevel('admin')
|
||||
->save();
|
||||
|
||||
Cache::forget('profiles:private');
|
||||
DeleteAccountPipeline::dispatch($user)->onQueue('high');
|
||||
|
||||
$msg = "Successfully deleted {$user->username}!";
|
||||
$request->session()->flash('status', $msg);
|
||||
return redirect('/i/admin/users/list');
|
||||
}
|
||||
|
||||
public function userModerate(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'profile_id' => 'required|exists:profiles,id',
|
||||
'action' => 'required|in:cw,no_autolink,unlisted'
|
||||
]);
|
||||
|
||||
$pid = $request->input('profile_id');
|
||||
$action = $request->input('action');
|
||||
$profile = Profile::findOrFail($pid);
|
||||
|
||||
if($profile->user->is_admin == true) {
|
||||
$mid = $request->user()->id;
|
||||
abort_if($profile->user_id < $mid, 403);
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'cw':
|
||||
$profile->cw = !$profile->cw;
|
||||
$msg = "Success!";
|
||||
break;
|
||||
|
||||
case 'no_autolink':
|
||||
$profile->no_autolink = !$profile->no_autolink;
|
||||
$msg = "Success!";
|
||||
break;
|
||||
|
||||
case 'unlisted':
|
||||
$profile->unlisted = !$profile->unlisted;
|
||||
$msg = "Success!";
|
||||
break;
|
||||
}
|
||||
|
||||
$profile->save();
|
||||
|
||||
ModLogService::boot()
|
||||
->objectUid($profile->user_id)
|
||||
->objectId($profile->user_id)
|
||||
->objectType('App\User::class')
|
||||
->user($request->user())
|
||||
->action('admin.user.moderate')
|
||||
->metadata([
|
||||
'action' => $action,
|
||||
'message' => $msg
|
||||
])
|
||||
->accessLevel('admin')
|
||||
->save();
|
||||
|
||||
$request->session()->flash('status', $msg);
|
||||
return redirect('/i/admin/users/modtools/' . $profile->user_id);
|
||||
}
|
||||
|
||||
public function userModLogDelete(Request $request, $id)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'mid' => 'required|integer|exists:mod_logs,id'
|
||||
]);
|
||||
$user = User::findOrFail($id);
|
||||
$uid = $request->user()->id;
|
||||
$mid = $request->input('mid');
|
||||
$ml = ModLog::whereUserId($uid)->findOrFail($mid)->delete();
|
||||
$msg = "Successfully deleted modlog comment!";
|
||||
$request->session()->flash('status', $msg);
|
||||
return redirect('/i/admin/users/modlogs/' . $user->id);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class AdminMessage extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
protected $msg;
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($msg)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$admins = config('pixelfed.domain.app') . ' admins';
|
||||
return $this->markdown('emails.notification.admin_message')
|
||||
->with(['msg' => $this->msg])
|
||||
->subject('Message from ' . $admins);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ModLog extends Model
|
||||
{
|
||||
protected $visible = ['id'];
|
||||
|
||||
public function admin()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
public function actionToText()
|
||||
{
|
||||
$msg = 'Unknown action';
|
||||
|
||||
switch ($this->action) {
|
||||
case 'admin.user.mail':
|
||||
$msg = "Sent Message";
|
||||
break;
|
||||
|
||||
case 'admin.user.action.cw.warn':
|
||||
$msg = "Sent CW reminder";
|
||||
break;
|
||||
|
||||
case 'admin.user.edit':
|
||||
$msg = "Changed Profile";
|
||||
break;
|
||||
|
||||
case 'admin.user.moderate':
|
||||
$msg = "Moderation";
|
||||
break;
|
||||
|
||||
case 'admin.user.delete':
|
||||
$msg = "Deleted Account";
|
||||
break;
|
||||
|
||||
default:
|
||||
$msg = 'Unknown action';
|
||||
break;
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\ModLog;
|
||||
use App\User;
|
||||
|
||||
class ModLogService {
|
||||
|
||||
protected $log;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->log = new \StdClass;
|
||||
}
|
||||
|
||||
public static function boot()
|
||||
{
|
||||
return new self;
|
||||
}
|
||||
|
||||
public function user(User $user)
|
||||
{
|
||||
$this->log->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function objectUid($val = null)
|
||||
{
|
||||
$this->log->object_uid = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function objectId($val = null)
|
||||
{
|
||||
$this->log->object_id = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function objectType($val = null)
|
||||
{
|
||||
$this->log->object_type = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function action($val = null)
|
||||
{
|
||||
$this->log->action = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function message($val = null)
|
||||
{
|
||||
$this->log->message = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function metadata(array $val = null)
|
||||
{
|
||||
$this->log->metadata = json_encode($val);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function accessLevel($val = null)
|
||||
{
|
||||
if(!in_array($val, ['admin', 'mod'])) {
|
||||
return $this;
|
||||
}
|
||||
$this->log->access_level = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function save($res = false)
|
||||
{
|
||||
$log = $this->log;
|
||||
if(!isset($log->user)) {
|
||||
throw new \Exception('Invalid ModLog attribute.');
|
||||
}
|
||||
|
||||
$ml = new ModLog();
|
||||
$ml->user_id = $log->user->id;
|
||||
$ml->user_username = $log->user->username;
|
||||
$ml->object_uid = $log->object_uid ?? null;
|
||||
$ml->object_id = $log->object_id ?? null;
|
||||
$ml->object_type = $log->object_type ?? null;
|
||||
$ml->action = $log->action ?? null;
|
||||
$ml->message = $log->message ?? null;
|
||||
$ml->metadata = $log->metadata ?? null;
|
||||
$ml->access_level = $log->access_level ?? 'admin';
|
||||
$ml->save();
|
||||
|
||||
if($res == true) {
|
||||
return $ml;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateModLogsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('mod_logs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('user_id')->unsigned()->index();
|
||||
$table->string('user_username')->nullable();
|
||||
$table->bigInteger('object_uid')->nullable()->unsigned()->index();
|
||||
$table->bigInteger('object_id')->nullable()->unsigned()->index();
|
||||
$table->string('object_type')->nullable()->index();
|
||||
$table->string('action')->nullable();
|
||||
$table->text('message')->nullable();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->string('access_level')->default('admin')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('mod_logs');
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="/i/admin/users/show/{{$user->id}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/show/{{$user->id}}">
|
||||
<span class="font-weight-bold">Overview</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/message/{{$user->id}}">
|
||||
<span class="font-weight-bold">Send Message</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/edit/{{$user->id}}">
|
||||
<span class="font-weight-bold">Edit</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modtools/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Tools</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modlogs/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Logs</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/delete/{{$user->id}}">
|
||||
<span class="text-danger font-weight-bold">Delete Account</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<p class="title h4 font-weight-bold mt-2 py-2">Recent Activity</p>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@if($logs->count() > 0)
|
||||
<div class="list-group">
|
||||
@foreach($logs as $log)
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<p class="small text-muted font-weight-bold mb-0">{{$log->created_at->diffForHumans()}}</p>
|
||||
<p class="lead mb-0">{{$log->message}}</p>
|
||||
<p class="small text-muted font-weight-bold mb-0">
|
||||
IP: {{$log->ip_address}}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-3">
|
||||
{{$logs->links()}}
|
||||
</div>
|
||||
@else
|
||||
<div class="card card-body border shadow-none text-center">
|
||||
No Activity found
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -0,0 +1,74 @@
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="/i/admin/users/show/{{$user->id}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/show/{{$user->id}}">
|
||||
<span class="font-weight-bold">Overview</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/activity/{{$user->id}}">
|
||||
<span class="font-weight-bold">Activity</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/message/{{$user->id}}">
|
||||
<span class="font-weight-bold">Send Message</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/edit/{{$user->id}}">
|
||||
<span class="font-weight-bold">Edit</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modtools/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Tools</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modlogs/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Logs</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<div class="card card-body">
|
||||
<p class="lead text-center py-5">Are you sure you want to delete this account?</p>
|
||||
<p class="mb-0">
|
||||
<form method="post" id="deleteForm">
|
||||
@csrf
|
||||
<button type="button" id="confirmDelete" class="btn btn-danger btn-block font-weight-bold">DELETE ACCOUNT</button>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
$('#confirmDelete').click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if(window.confirm('Are you sure you want to delete this account?') == true) {
|
||||
if(window.confirm('Are you absolutely sure you want to delete this account?') == true) {
|
||||
$('#deleteForm').submit();
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -1,101 +1,100 @@
|
||||
@extends('admin.partial.template')
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between">
|
||||
<h3 class="font-weight-bold">Edit User</h3>
|
||||
<span><a href="{{route('admin.users')}}" class="btn btn-outline-primary btn-sm font-weight-bold">Back</a></span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="/i/admin/users/show/{{$user->id}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/show/{{$user->id}}">
|
||||
<span class="font-weight-bold">Overview</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/activity/{{$user->id}}">
|
||||
<span class="font-weight-bold">Activity</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/message/{{$user->id}}">
|
||||
<span class="font-weight-bold">Send Message</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/modtools/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Tools</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modlogs/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Logs</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/delete/{{$user->id}}">
|
||||
<span class="text-danger font-weight-bold">Delete Account</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h4 mb-0 font-weight-bold">{{$profile->statusCount()}}</p>
|
||||
<p class="text-muted font-weight-bold small mb-0">Posts</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h4 mb-0 font-weight-bold">{{$profile->likes()->count()}}</p>
|
||||
<p class="text-muted font-weight-bold small mb-0">Likes</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h4 mb-0 font-weight-bold">{{$profile->reports()->count()}}</p>
|
||||
<p class="text-muted font-weight-bold small mb-0">Reports</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="h4 mb-0 font-weight-bold">{{PrettyNumber::size($profile->media()->sum('size'))}}</p>
|
||||
<p class="text-muted font-weight-bold small mb-0">Storage Used</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<p class="title h4 font-weight-bold mt-2 py-2">Edit</p>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<form method="post">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Display Name</label>
|
||||
<input type="text" class="form-control" name="name" value="{{$user->name}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Username</label>
|
||||
<input type="text" class="form-control" name="username" value="{{$user->username}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Email address</label>
|
||||
<input type="email" class="form-control" name="email" value="{{$user->email}}" placeholder="Enter email">
|
||||
<p class="help-text small text-muted font-weight-bold">
|
||||
@if($user->email_verified_at)
|
||||
<span class="text-success">Verified</span> for {{$user->email_verified_at->diffForHumans()}}
|
||||
@else
|
||||
<span class="text-danger">Unverified</span> email.
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Bio</label>
|
||||
<textarea class="form-control" rows="4" name="bio" placeholder="Empty bio">{{$profile->bio}}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Website</label>
|
||||
<input type="text" class="form-control" name="website" value="{{$user->website}}" placeholder="No website added">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Admin</label>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="customSwitch1" {{$user->is_admin ? 'checked="checked"' : ''}}>
|
||||
<label class="custom-control-label" for="customSwitch1"></label>
|
||||
</div>
|
||||
<p class="help-text small text-muted font-weight-bold">For security reasons, you cannot change admin status on this form. Use the CLI instead.</p>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="float-right">
|
||||
<button type="submit" class="btn btn-primary font-weight-bold py-1">SAVE</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<img src="{{$profile->avatarUrl()}}" class="img-thumbnail rounded-circle" width="128px" height="128px">
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<p class="font-weight-bold mb-0 small">Last updated: {{$profile->avatar->updated_at->diffForHumans()}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body p-5 d-flex justify-content-center align-items-center">
|
||||
<div class="text-center py-3">
|
||||
<p class="font-weight-bold mb-0">
|
||||
{{$profile->username}}
|
||||
</p>
|
||||
<p class="h3 font-weight-bold">
|
||||
{{$profile->emailUrl()}}
|
||||
</p>
|
||||
<p class="font-weight-bold mb-0 text-muted">
|
||||
Member Since: {{$profile->created_at->format('M Y')}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="mx-3">
|
||||
<div class="sub-title h4 font-weight-bold mb-4">
|
||||
Account Settings
|
||||
</div>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Display Name</label>
|
||||
<input type="text" class="form-control" value="{{$user->name}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Username</label>
|
||||
<input type="text" class="form-control" value="{{$user->username}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted">Email address</label>
|
||||
<input type="email" class="form-control" value="{{$user->email}}" placeholder="Enter email">
|
||||
<p class="help-text small text-muted font-weight-bold">
|
||||
@if($user->email_verified_at)
|
||||
<span class="text-success">Verified</span> for {{$user->email_verified_at->diffForHumans()}}
|
||||
@else
|
||||
<span class="text-danger">Unverified</span> email.
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
@ -0,0 +1,112 @@
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="/i/admin/users/show/{{$user->id}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/show/{{$user->id}}">
|
||||
<span class="font-weight-bold">Overview</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/edit/{{$user->id}}">
|
||||
<span class="font-weight-bold">Edit</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modtools/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Tools</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modlogs/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Logs</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/delete/{{$user->id}}">
|
||||
<span class="text-danger font-weight-bold">Delete Account</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<p class="title h4 font-weight-bold mt-2 py-2">Send Message</p>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
<form method="post" id="messageForm">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<textarea class="form-control" rows="8" placeholder="Message body ..." id="message" name="message"></textarea>
|
||||
<p class="help-text mb-0 small text-muted">
|
||||
<span>Plain text only, html will not be rendered.</span>
|
||||
<span class="float-right msg-counter"><span class="msg-count">0</span>/500</span>
|
||||
</p>
|
||||
</div>
|
||||
<p class="float-right">
|
||||
<button type="button" class="btn btn-primary py-1 font-weight-bold" onclick="submitWarning()"><i class="fas fa-message"></i> SEND</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
$('#message').on('keyup change paste submit', function(e) {
|
||||
let len = e.target.value.length;
|
||||
$('.msg-count').text(len);
|
||||
});
|
||||
function submitWarning() {
|
||||
let msg = document.querySelector('#message');
|
||||
if(msg.value.length < 5) {
|
||||
swal('Oops!', 'Your message must be longer than 5 characters.', 'error');
|
||||
return;
|
||||
}
|
||||
if(msg.value.length > 500) {
|
||||
swal('Oops!', 'Your message must be shorter than 500 characters.', 'error');
|
||||
return;
|
||||
}
|
||||
swal({
|
||||
title: "Are you sure?",
|
||||
text: "Are you sure you want to send this message to {{$user->username}}?",
|
||||
icon: "warning",
|
||||
buttons: true,
|
||||
dangerMode: true,
|
||||
})
|
||||
.then((sendMessage) => {
|
||||
if (sendMessage) {
|
||||
$('#messageForm').submit();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,159 @@
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="/i/admin/users/show/{{$user->id}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/show/{{$user->id}}">
|
||||
<span class="font-weight-bold">Overview</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/activity/{{$user->id}}">
|
||||
<span class="font-weight-bold">Activity</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/message/{{$user->id}}">
|
||||
<span class="font-weight-bold">Send Message</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/edit/{{$user->id}}">
|
||||
<span class="font-weight-bold">Edit</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modtools/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Tools</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/delete/{{$user->id}}">
|
||||
<span class="text-danger font-weight-bold">Delete Account</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<p class="title h4 font-weight-bold mt-2 py-2">Moderation Logs</p>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card card-body shadow-none border mb-3">
|
||||
<form method="post">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<textarea class="form-control" name="message" id="message" rows="4" style="resize: none;" placeholder="Send a message to other admins and mods, they will be notified"></textarea>
|
||||
@if ($errors->any())
|
||||
@foreach ($errors->all() as $error)
|
||||
<p class="invalid-feedback mb-0" style="display:block;">
|
||||
<strong>{{ $error }}</strong>
|
||||
</p>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<span class="small text-muted font-weight-bold">
|
||||
<span class="msg-count">0</span>/500
|
||||
</span>
|
||||
<span class="float-right">
|
||||
<button class="btn btn-primary btn-sm py-1 font-weight-bold">SEND</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@if($logs->count() > 0)
|
||||
<div class="list-group">
|
||||
@foreach($logs as $log)
|
||||
<div class="list-group-item">
|
||||
@if($log->message != null)
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="mr-3">
|
||||
<img src="{{$log->admin->profile->avatarUrl()}}" width="40px" height="40px" class="border p-1 rounded-circle">
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
@if($log->user_id != Auth::id())
|
||||
<div class="p-3 bg-primary rounded">
|
||||
<p class="mb-0 text-white" style="font-weight: 600;">{{$log->message}}</p>
|
||||
</div>
|
||||
@else
|
||||
<div class="p-3 bg-white border rounded">
|
||||
<p class="mb-0 text-dark" style="font-weight: 600;">{{$log->message}}</p>
|
||||
</div>
|
||||
@endif
|
||||
<div class="d-flex justify-content-between small text-muted font-weight-bold mb-0 pt-2">
|
||||
<span class="mr-4">
|
||||
@{{$log->user_username}}
|
||||
</span>
|
||||
<span>
|
||||
{{$log->created_at->diffForHumans()}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@if($log->user_id == Auth::id())
|
||||
<div class="align-self-top ml-2">
|
||||
<form method="post" action="/i/admin/users/modlogs/{{$user->id}}/delete">
|
||||
@csrf
|
||||
<input type="hidden" name="mid" value="{{$log->id}}">
|
||||
<button type="submit" class="btn btn-text">
|
||||
<i class="fas fa-times text-lighter"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="mr-3">
|
||||
<img src="{{$log->admin->profile->avatarUrl()}}" width="40px" height="40px" class="border p-1 rounded-circle">
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
<p class="small text-muted font-weight-bold mb-0">{{$log->created_at->diffForHumans()}}</p>
|
||||
<p class="lead mb-0">{{$log->actionToText()}}</p>
|
||||
<p class="small text-muted font-weight-bold mb-0">
|
||||
by: {{$log->user_username}}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-3">
|
||||
{{$logs->links()}}
|
||||
</div>
|
||||
@else
|
||||
<div class="card card-body border shadow-none text-center">
|
||||
No Activity found
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
$('#message').on('keyup change paste submit', function(e) {
|
||||
let len = e.target.value.length;
|
||||
$('.msg-count').text(len);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,90 @@
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="/i/admin/users/show/{{$user->id}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/show/{{$user->id}}">
|
||||
<span class="font-weight-bold">Overview</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/activity/{{$user->id}}">
|
||||
<span class="font-weight-bold">Activity</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/message/{{$user->id}}">
|
||||
<span class="font-weight-bold">Send Message</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/edit/{{$user->id}}">
|
||||
<span class="font-weight-bold">Edit</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modlogs/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Logs</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/delete/{{$user->id}}">
|
||||
<span class="text-danger font-weight-bold">Delete Account</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<p class="title h4 font-weight-bold mt-2 py-2">Mod Tools</p>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<form method="post" action="/i/admin/users/moderation/update" class="pb-3">
|
||||
@csrf
|
||||
<input type="hidden" name="action" value="cw">
|
||||
<input type="hidden" name="profile_id" value="{{$profile->id}}">
|
||||
<button class="btn btn-outline-{{$profile->cw ? 'secondary' : 'primary'}} py-0 font-weight-bold">
|
||||
{{$profile->cw ? 'Remove CW Enforcement' : 'Enforce CW'}}
|
||||
</button>
|
||||
<p class="help-text text-muted font-weight-bold small">Adds a CW to every post made by this account.</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<form method="post" action="/i/admin/users/moderation/update" class="pb-3">
|
||||
@csrf
|
||||
<input type="hidden" name="action" value="unlisted">
|
||||
<input type="hidden" name="profile_id" value="{{$profile->id}}">
|
||||
<button class="btn btn-outline-{{$profile->unlisted ? 'secondary' : 'primary'}} py-0 font-weight-bold">
|
||||
{{$profile->unlisted ? 'Remove Unlisting' : 'Unlisted Posts'}}
|
||||
</button>
|
||||
<p class="help-text text-muted font-weight-bold small">Removes account from public/network timelines.</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<form method="post" action="/i/admin/users/moderation/update" class="pb-3">
|
||||
@csrf
|
||||
<input type="hidden" name="action" value="no_autolink">
|
||||
<input type="hidden" name="profile_id" value="{{$profile->id}}">
|
||||
<button class="btn btn-outline-{{$profile->no_autolink ? 'secondary' : 'primary'}} py-0 font-weight-bold">
|
||||
{{$profile->no_autolink ? 'Remove No Autolinking' : 'No Autolinking'}}
|
||||
</button>
|
||||
<p class="help-text text-muted font-weight-bold small">Do not transform mentions, hashtags or urls into HTML.</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -0,0 +1,121 @@
|
||||
@extends('admin.partial.template-full')
|
||||
|
||||
@section('section')
|
||||
<div class="title d-flex justify-content-between align-items-center">
|
||||
<span><a href="{{route('admin.users')}}" class="btn btn-outline-secondary btn-sm font-weight-bold">Back</a></span>
|
||||
<span class="text-center">
|
||||
<h3 class="font-weight-bold mb-0">@{{$profile->username}}</h3>
|
||||
<p class="mb-0 small text-muted text-uppercase font-weight-bold">
|
||||
<span>{{$profile->statuses()->count()}} Posts</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->followers()->count()}} Followers</span>
|
||||
<span class="px-1">|</span>
|
||||
<span>{{$profile->following()->count()}} Following</span>
|
||||
</p>
|
||||
</span>
|
||||
<span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm font-weight-bold dropdown-toggle" type="button" id="userActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-bars"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userActions">
|
||||
<a class="dropdown-item" href="/i/admin/users/activity/{{$user->id}}">
|
||||
<span class="font-weight-bold">Activity</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/message/{{$user->id}}">
|
||||
<span class="font-weight-bold">Send Message</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{$profile->url()}}">
|
||||
<span class="font-weight-bold">View Profile</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/edit/{{$user->id}}">
|
||||
<span class="font-weight-bold">Edit</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modtools/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Tools</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/i/admin/users/modlogs/{{$user->id}}">
|
||||
<span class="font-weight-bold">Mod Logs</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/i/admin/users/delete/{{$user->id}}">
|
||||
<span class="text-danger font-weight-bold">Delete Account</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="card shadow-none border">
|
||||
<div class="card-body text-center">
|
||||
<img src="{{$profile->avatarUrl()}}" class="box-shadow rounded-circle" width="128px" height="128px">
|
||||
<p class="mt-3 mb-0 lead">
|
||||
<span class="font-weight-bold">{{$profile->name}}</span>
|
||||
</p>
|
||||
@if($user->is_admin == true)
|
||||
<p class="mb-0">
|
||||
<span class="badge badge-danger badge-sm">ADMIN</span>
|
||||
</p>
|
||||
@endif
|
||||
<p class="mb-0 text-center text-muted">
|
||||
Joined {{$profile->created_at->diffForHumans()}}
|
||||
</p>
|
||||
</div>
|
||||
<table class="table mb-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">bookmarks</th>
|
||||
<td class="text-right font-weight-bold">{{$profile->bookmarks()->count()}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">collections</th>
|
||||
<td class="text-right font-weight-bold">{{$profile->collections()->count()}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">likes</th>
|
||||
<td class="text-right font-weight-bold">{{$profile->likes()->count()}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">reports</th>
|
||||
<td class="text-right font-weight-bold">{{$profile->reports()->count()}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">reported</th>
|
||||
<td class="text-right font-weight-bold">{{$profile->reported()->count()}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">Active stories</th>
|
||||
<td class="text-right font-weight-bold">{{$profile->stories()->count()}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row" class="font-weight-bold text-muted text-uppercase pl-3 small" style="line-height: 2;">storage used</th>
|
||||
<td class="text-right font-weight-bold">{{PrettyNumber::size($profile->media()->sum('size'))}}<span class="text-muted"> / {{PrettyNumber::size(config('pixelfed.max_account_size') * 1000)}}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<p class="title h4 font-weight-bold mt-2 py-2">Recent Posts</p>
|
||||
<hr>
|
||||
<div class="row">
|
||||
@foreach($profile->statuses()->whereHas('media')->latest()->take(9)->get() as $item)
|
||||
<div class="col-12 col-md-4 col-sm-6 px-0" style="margin-bottom: 1px;">
|
||||
<a href="{{$item->url()}}">
|
||||
<img src="{{$item->thumb(true)}}" width="200px" height="200px">
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@if($profile->statuses()->whereHas('media')->count() == 0)
|
||||
<div class="col-12">
|
||||
<div class="card card-body border shadow-none bg-transparent">
|
||||
<p class="text-center mb-0 text-muted">No statuses found</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -0,0 +1,20 @@
|
||||
@component('mail::message')
|
||||
# Message from {{ config('pixelfed.domain.app') }}:
|
||||
|
||||
|
||||
@component('mail::panel')
|
||||
{{$msg}}
|
||||
@endcomponent
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
Regards,<br>
|
||||
{{ config('pixelfed.domain.app') }}
|
||||
|
||||
@component('mail::subcopy')
|
||||
Please do not reply to this email, this address is not monitored.
|
||||
@endcomponent
|
||||
|
||||
@endcomponent
|
||||
|
@ -1,41 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="container px-0 mt-md-4">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
|
||||
<div class="card shadow-none border">
|
||||
<div class="card-body">
|
||||
<p class="mb-0">
|
||||
<img class="img-thumbnail mr-2" src="{{$profile->avatarUrl()}}" width="24px" height="24px" style="border-radius:24px;">
|
||||
<span class="font-weight-bold pr-1"><bdi><a class="text-dark" href="{{$status->profile->url()}}">{{ str_limit($status->profile->username, 15)}}</a></bdi></span>
|
||||
<span class="comment-text">{!! $status->rendered ?? e($status->caption) !!} <a href="{{$status->url()}}" class="text-dark small font-weight-bold float-right pl-2">{{$status->created_at->diffForHumans(null, true, true ,true)}}</a></span>
|
||||
</p>
|
||||
<p class="text-center font-weight-bold text-muted small text-uppercase pt-3">All Comments</p>
|
||||
<div class="comments">
|
||||
@foreach($replies as $item)
|
||||
<p class="mb-2">
|
||||
<span class="font-weight-bold pr-1">
|
||||
<img class="img-thumbnail mr-2" src="{{$item->profile->avatarUrl()}}" width="24px" height="24px" style="border-radius:24px;">
|
||||
<bdi><a class="text-dark" href="{{$item->profile->url()}}">{{ str_limit($item->profile->username, 15)}}</a></bdi>
|
||||
</span>
|
||||
<span class="comment-text">
|
||||
{!! $item->rendered ?? e($item->caption) !!}
|
||||
<a href="{{$item->url()}}" class="text-dark small font-weight-bold float-right pl-2">
|
||||
{{$item->created_at->diffForHumans(null, true, true ,true)}}
|
||||
</a>
|
||||
</span>
|
||||
</p>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-center">
|
||||
{{ $replies->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
Loading…
Reference in New Issue