Apply fixes from StyleCI

This commit is contained in:
daniel 2018-08-28 03:07:36 +00:00 committed by StyleCI Bot
parent 75de27f482
commit b8abbdd90f
261 changed files with 3368 additions and 3231 deletions

View file

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Media;
use App\Jobs\ImageOptimizePipeline\ImageOptimize;
use App\Media;
use Illuminate\Console\Command;
class CatchUnoptimizedMedia extends Command
{
@ -40,7 +40,7 @@ class CatchUnoptimizedMedia extends Command
public function handle()
{
$medias = Media::whereNull('processed_at')->take(50)->get();
foreach($medias as $media) {
foreach ($medias as $media) {
ImageOptimize::dispatch($media);
}
}

View file

@ -2,9 +2,10 @@
namespace App\Console\Commands;
use App\{Follower, Profile};
use Illuminate\Console\Command;
use App\Follower;
use App\Jobs\FollowPipeline\FollowPipeline;
use App\Profile;
use Illuminate\Console\Command;
class SeedFollows extends Command
{
@ -41,12 +42,12 @@ class SeedFollows extends Command
{
$limit = 10000;
for ($i=0; $i < $limit; $i++) {
for ($i = 0; $i < $limit; $i++) {
try {
$actor = Profile::inRandomOrder()->firstOrFail();
$target = Profile::inRandomOrder()->firstOrFail();
$follow = new Follower;
$follow = new Follower();
$follow->profile_id = $actor->id;
$follow->following_id = $target->id;
$follow->save();

View file

@ -20,6 +20,7 @@ class Kernel extends ConsoleKernel
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void
*/
protected function schedule(Schedule $schedule)

View file

@ -9,7 +9,8 @@ class EmailVerification extends Model
public function url()
{
$base = config('app.url');
$path = '/i/confirm-email/' . $this->user_token . '/' . $this->random_token;
$path = '/i/confirm-email/'.$this->user_token.'/'.$this->random_token;
return "{$base}{$path}";
}
}

View file

@ -2,14 +2,11 @@
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use App\User;
use App\UserSetting;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\{User, UserSetting};
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class AuthLoginEvent
{
@ -27,8 +24,8 @@ class AuthLoginEvent
public function handle(User $user)
{
if(empty($user->settings)) {
$settings = new UserSetting;
if (empty($user->settings)) {
$settings = new UserSetting();
$settings->user_id = $user->id;
$settings->save();
}

View file

@ -30,6 +30,7 @@ class Handler extends ExceptionHandler
* Report or log an exception.
*
* @param \Exception $exception
*
* @return void
*/
public function report(Exception $exception)
@ -42,6 +43,7 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
*
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)

View file

@ -24,14 +24,16 @@ class Follower extends Model
public function toText()
{
$actorName = $this->actor->username;
return "{$actorName} " . __('notification.startedFollowingYou');
return "{$actorName} ".__('notification.startedFollowingYou');
}
public function toHtml()
{
$actorName = $this->actor->username;
$actorUrl = $this->actor->url();
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> " .
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> ".
__('notification.startedFollowingYou');
}
}

View file

@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model;
class Hashtag extends Model
{
public $fillable = ['name','slug'];
public $fillable = ['name', 'slug'];
public function posts()
{
@ -22,7 +22,6 @@ class Hashtag extends Model
public function url()
{
return config('routes.hashtag.base') . $this->slug;
return config('routes.hashtag.base').$this->slug;
}
}

View file

@ -2,23 +2,24 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\EmailVerification;
use App\Mail\ConfirmEmail;
use Auth, DB, Cache, Mail, Redis;
use App\{
EmailVerification,
Notification,
Profile,
User,
UserFilter
};
use App\Notification;
use App\Profile;
use App\User;
use App\UserFilter;
use Auth;
use Cache;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Mail;
use Redis;
class AccountController extends Controller
{
protected $filters = [
'user.mute',
'user.block'
'user.block',
];
public function __construct()
@ -35,16 +36,16 @@ class AccountController extends Controller
$profile = Auth::user()->profile;
$action = $request->input('a');
$timeago = Carbon::now()->subMonths(6);
if($action && in_array($action, ['comment', 'follow', 'mention'])) {
if ($action && in_array($action, ['comment', 'follow', 'mention'])) {
$notifications = Notification::whereProfileId($profile->id)
->whereAction($action)
->whereDate('created_at', '>', $timeago)
->orderBy('id','desc')
->orderBy('id', 'desc')
->simplePaginate(30);
} else {
$notifications = Notification::whereProfileId($profile->id)
->whereDate('created_at', '>', $timeago)
->orderBy('id','desc')
->orderBy('id', 'desc')
->simplePaginate(30);
}
@ -64,7 +65,7 @@ class AccountController extends Controller
$notifications = Notification::whereIn('actor_id', $following)
->where('profile_id', '!=', $profile->id)
->whereDate('created_at', '>', $timeago)
->orderBy('notifications.id','desc')
->orderBy('notifications.id', 'desc')
->simplePaginate(30);
return view('account.following', compact('profile', 'notifications'));
@ -82,19 +83,18 @@ class AccountController extends Controller
->where('created_at', '>', $timeLimit)->count();
$exists = EmailVerification::whereUserId(Auth::id())->count();
if($recentAttempt == 1 && $exists == 1) {
if ($recentAttempt == 1 && $exists == 1) {
return redirect()->back()->with('error', 'A verification email has already been sent recently. Please check your email, or try again later.');
} elseif ($recentAttempt == 0 && $exists !== 0) {
// Delete old verification and send new one.
EmailVerification::whereUserId(Auth::id())->delete();
}
$user = User::whereNull('email_verified_at')->find(Auth::id());
$utoken = hash('sha512', $user->id);
$rtoken = str_random(40);
$verify = new EmailVerification;
$verify = new EmailVerification();
$verify->user_id = $user->id;
$verify->email = $user->email;
$verify->user_token = $utoken;
@ -112,22 +112,23 @@ class AccountController extends Controller
->where('random_token', $randomToken)
->firstOrFail();
if(Auth::id() === $verify->user_id) {
if (Auth::id() === $verify->user_id) {
$user = User::find(Auth::id());
$user->email_verified_at = Carbon::now();
$user->save();
return redirect('/');
}
}
public function fetchNotifications($id)
{
$key = config('cache.prefix') . ":user.{$id}.notifications";
$key = config('cache.prefix').":user.{$id}.notifications";
$redis = Redis::connection();
$notifications = $redis->lrange($key, 0, 30);
if(empty($notifications)) {
if (empty($notifications)) {
$notifications = Notification::whereProfileId($id)
->orderBy('id','desc')->take(30)->get();
->orderBy('id', 'desc')->take(30)->get();
} else {
$notifications = $this->hydrateNotifications($notifications);
}
@ -139,9 +140,10 @@ class AccountController extends Controller
{
$prefix = 'notification.';
$notifications = collect([]);
foreach($keys as $key) {
foreach ($keys as $key) {
$notifications->push(Cache::get("{$prefix}{$key}"));
}
return $notifications;
}
@ -150,7 +152,6 @@ class AccountController extends Controller
return view('account.messages');
}
public function showMessage(Request $request, $id)
{
return view('account.message');
@ -160,7 +161,7 @@ class AccountController extends Controller
{
$this->validate($request, [
'type' => 'required|string',
'item' => 'required|integer|min:1'
'item' => 'required|integer|min:1',
]);
$user = Auth::user()->profile;
@ -168,14 +169,14 @@ class AccountController extends Controller
$item = $request->input('item');
$action = "{$type}.mute";
if(!in_array($action, $this->filters)) {
if (!in_array($action, $this->filters)) {
return abort(406);
}
$filterable = [];
switch ($type) {
case 'user':
$profile = Profile::findOrFail($item);
if($profile->id == $user->id) {
if ($profile->id == $user->id) {
return abort(403);
}
$class = get_class($profile);
@ -184,7 +185,7 @@ class AccountController extends Controller
break;
default:
# code...
// code...
break;
}
@ -192,25 +193,24 @@ class AccountController extends Controller
'user_id' => $user->id,
'filterable_id' => $filterable['id'],
'filterable_type' => $filterable['type'],
'filter_type' => 'mute'
'filter_type' => 'mute',
]);
return redirect()->back();
}
public function block(Request $request)
{
$this->validate($request, [
'type' => 'required|string',
'item' => 'required|integer|min:1'
'item' => 'required|integer|min:1',
]);
$user = Auth::user()->profile;
$type = $request->input('type');
$item = $request->input('item');
$action = "{$type}.block";
if(!in_array($action, $this->filters)) {
if (!in_array($action, $this->filters)) {
return abort(406);
}
$filterable = [];
@ -223,7 +223,7 @@ class AccountController extends Controller
break;
default:
# code...
// code...
break;
}
@ -231,11 +231,9 @@ class AccountController extends Controller
'user_id' => $user->id,
'filterable_id' => $filterable['id'],
'filterable_type' => $filterable['type'],
'filter_type' => 'block'
'filter_type' => 'block',
]);
return redirect()->back();
}
}

View file

@ -2,17 +2,16 @@
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Report;
use Carbon\Carbon;
use App\{Comment, Like, Media, Profile, Report, Status, User};
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
trait AdminReportController
{
public function updateReport(Request $request, $id)
{
$this->validate($request, [
'action' => 'required|string'
'action' => 'required|string',
]);
$action = $request->input('action');
@ -23,10 +22,10 @@ trait AdminReportController
'unlist',
'delete',
'shadowban',
'ban'
'ban',
];
if(!in_array($action, $actions)) {
if (!in_array($action, $actions)) {
return abort(403);
}

View file

@ -2,8 +2,10 @@
namespace App\Http\Controllers;
use App\Media;
use App\Status;
use App\User;
use Illuminate\Http\Request;
use App\{Comment, Like, Media, Profile, Status, User};
class AdminController extends Controller
{
@ -20,25 +22,28 @@ class AdminController extends Controller
public function users(Request $request)
{
$users = User::orderBy('id', 'desc')->paginate(10);
return view('admin.users.home', compact('users'));
}
public function statuses(Request $request)
{
$statuses = Status::orderBy('id', 'desc')->paginate(10);
return view('admin.statuses.home', compact('statuses'));
}
public function showStatus(Request $request, $id)
{
$status = Status::findOrFail($id);
return view('admin.statuses.show', compact('status'));
}
public function media(Request $request)
{
$media = Status::whereHas('media')->orderby('id', 'desc')->paginate(12);
return view('admin.media.home', compact('media'));
}
}

View file

@ -2,23 +2,17 @@
namespace App\Http\Controllers\Api;
use Auth, Cache;
use App\{
Avatar,
Like,
Profile,
Status
};
use League\Fractal;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Avatar;
use App\Http\Controllers\AvatarController;
use App\Util\Webfinger\Webfinger;
use App\Transformer\Api\{
AccountTransformer,
StatusTransformer
};
use App\Http\Controllers\Controller;
use App\Jobs\AvatarPipeline\AvatarOptimize;
use App\Profile;
use App\Transformer\Api\AccountTransformer;
use App\Transformer\Api\StatusTransformer;
use Auth;
use Cache;
use Illuminate\Http\Request;
use League\Fractal;
use League\Fractal\Serializer\ArraySerializer;
class BaseApiController extends Controller
@ -35,8 +29,9 @@ class BaseApiController extends Controller
public function accounts(Request $request, $id)
{
$profile = Profile::findOrFail($id);
$resource = new Fractal\Resource\Item($profile, new AccountTransformer);
$resource = new Fractal\Resource\Item($profile, new AccountTransformer());
$res = $this->fractal->createData($resource)->toArray();
return response()->json($res, 200, [], JSON_PRETTY_PRINT);
}
@ -44,8 +39,9 @@ class BaseApiController extends Controller
{
$profile = Profile::findOrFail($id);
$followers = $profile->followers;
$resource = new Fractal\Resource\Collection($followers, new AccountTransformer);
$resource = new Fractal\Resource\Collection($followers, new AccountTransformer());
$res = $this->fractal->createData($resource)->toArray();
return response()->json($res, 200, [], JSON_PRETTY_PRINT);
}
@ -53,8 +49,9 @@ class BaseApiController extends Controller
{
$profile = Profile::findOrFail($id);
$following = $profile->following;
$resource = new Fractal\Resource\Collection($following, new AccountTransformer);
$resource = new Fractal\Resource\Collection($following, new AccountTransformer());
$res = $this->fractal->createData($resource)->toArray();
return response()->json($res, 200, [], JSON_PRETTY_PRINT);
}
@ -62,17 +59,18 @@ class BaseApiController extends Controller
{
$profile = Profile::findOrFail($id);
$statuses = $profile->statuses()->orderBy('id', 'desc')->paginate(20);
$resource = new Fractal\Resource\Collection($statuses, new StatusTransformer);
$resource = new Fractal\Resource\Collection($statuses, new StatusTransformer());
$res = $this->fractal->createData($resource)->toArray();
return response()->json($res, 200, [], JSON_PRETTY_PRINT);
}
public function followSuggestions(Request $request)
{
$followers = Auth::user()->profile->recommendFollowers();
$resource = new Fractal\Resource\Collection($followers, new AccountTransformer);
$resource = new Fractal\Resource\Collection($followers, new AccountTransformer());
$res = $this->fractal->createData($resource)->toArray();
return response()->json($res);
}
@ -81,6 +79,7 @@ class BaseApiController extends Controller
$this->validate($request, [
'upload' => 'required|mimes:jpeg,png,gif|max:2000',
]);
try {
$user = Auth::user();
$profile = $user->profile;
@ -107,7 +106,7 @@ class BaseApiController extends Controller
return response()->json([
'code' => 200,
'msg' => 'Avatar successfully updated'
'msg' => 'Avatar successfully updated',
]);
}
}

View file

@ -2,14 +2,14 @@
namespace App\Http\Controllers;
use Auth, Cache;
use App\{Like, Status};
use Illuminate\Http\Request;
use App\Http\Controllers\Api\BaseApiController;
use App\Like;
use Auth;
use Cache;
use Illuminate\Http\Request;
class ApiController extends BaseApiController
{
public function hydrateLikes(Request $request)
{
$this->validate($request, [
@ -18,7 +18,7 @@ class ApiController extends BaseApiController
]);
$profile = Auth::user()->profile;
$res = Cache::remember('api:like-ids:user:'.$profile->id, 1440, function() use ($profile) {
$res = Cache::remember('api:like-ids:user:'.$profile->id, 1440, function () use ($profile) {
return Like::whereProfileId($profile->id)
->orderBy('id', 'desc')
->take(1000)
@ -30,6 +30,5 @@ class ApiController extends BaseApiController
public function loadMoreComments(Request $request)
{
return;
}
}

View file

@ -2,8 +2,9 @@
namespace App\Http\Controllers\Auth;
use App\{AccountLog, User};
use App\AccountLog;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
@ -42,6 +43,7 @@ class LoginController extends Controller
* Validate the user login request.
*
* @param \Illuminate\Http\Request $request
*
* @return void
*/
public function validateLogin($request)
@ -51,7 +53,7 @@ class LoginController extends Controller
'password' => 'required|string',
];
if(config('pixelfed.recaptcha')) {
if (config('pixelfed.recaptcha')) {
$rules['g-recaptcha-response'] = 'required|recaptcha';
}
@ -63,11 +65,12 @@ class LoginController extends Controller
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
*
* @return mixed
*/
protected function authenticated($request, $user)
{
$log = new AccountLog;
$log = new AccountLog();
$log->user_id = $user->id;
$log->item_id = $user->id;
$log->item_type = 'App\User';

View file

@ -2,12 +2,12 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\User;
use App\Util\Lexer\RestrictedNames;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
class RegisterController extends Controller
{
@ -46,6 +46,7 @@ class RegisterController extends Controller
* Get a validator for an incoming registration request.
*
* @param array $data
*
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
@ -57,21 +58,21 @@ class RegisterController extends Controller
'min:2',
'max:15',
'unique:users',
function($attribute, $value, $fail) {
if(!ctype_alpha($value[0])) {
return $fail($attribute . ' is invalid. Username must be alpha-numeric and start with a letter.');
}
function ($attribute, $value, $fail) {
if (!ctype_alpha($value[0])) {
return $fail($attribute.' is invalid. Username must be alpha-numeric and start with a letter.');
}
},
];
$rules = [
'name' => 'required|string|max:' . config('pixelfed.max_name_length'),
'name' => 'required|string|max:'.config('pixelfed.max_name_length'),
'username' => $usernameRules,
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
];
if(config('pixelfed.recaptcha')) {
if (config('pixelfed.recaptcha')) {
$rules['g-recaptcha-response'] = 'required|recaptcha';
}
@ -82,6 +83,7 @@ class RegisterController extends Controller
* Create a new user instance after a valid registration.
*
* @param array $data
*
* @return \App\User
*/
protected function create(array $data)
@ -98,7 +100,7 @@ class RegisterController extends Controller
{
$restricted = RestrictedNames::get();
if(in_array($username, $restricted)) {
if (in_array($username, $restricted)) {
return abort(403);
}
}
@ -106,7 +108,7 @@ class RegisterController extends Controller
public function openRegistrationCheck()
{
$openRegistration = config('pixelfed.open_registration');
if(false == $openRegistration) {
if (false == $openRegistration) {
abort(403);
}
}

View file

@ -2,10 +2,12 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth, Cache, Log, Storage;
use App\Avatar;
use App\Jobs\AvatarPipeline\AvatarOptimize;
use Auth;
use Cache;
use Illuminate\Http\Request;
use Storage;
class AvatarController extends Controller
{
@ -17,8 +19,9 @@ class AvatarController extends Controller
public function store(Request $request)
{
$this->validate($request, [
'avatar' => 'required|mimes:jpeg,png|max:2000'
'avatar' => 'required|mimes:jpeg,png|max:2000',
]);
try {
$user = Auth::user();
$profile = $user->profile;
@ -42,6 +45,7 @@ class AvatarController extends Controller
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.');
}
@ -54,15 +58,15 @@ class AvatarController extends Controller
$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];
$name = 'avatar.'.$file->guessExtension();
$res = ['root' => 'storage/app/'.$path, 'name' => $name, 'storage' => $path];
return $res;
}
public function checkDir($path)
{
if(!is_dir($path)) {
if (!is_dir($path)) {
mkdir($path);
}
}
@ -71,25 +75,26 @@ class AvatarController extends Controller
{
$padded = str_pad($id, 12, 0, STR_PAD_LEFT);
$parts = str_split($padded, 3);
foreach($parts as $k => $part) {
if($k == 0) {
foreach ($parts as $k => $part) {
if ($k == 0) {
$prefix = storage_path('app/public/avatars/'.$parts[0]);
$this->checkDir($prefix);
}
if($k == 1) {
if ($k == 1) {
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1]);
$this->checkDir($prefix);
}
if($k == 2) {
if ($k == 2) {
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2]);
$this->checkDir($prefix);
}
if($k == 3) {
if ($k == 3) {
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3];
$prefix = storage_path('app/'.$avatarpath);
$this->checkDir($prefix);
}
}
return $avatarpath;
}
}

View file

@ -2,8 +2,9 @@
namespace App\Http\Controllers;
use App\Bookmark;
use App\Status;
use Auth;
use App\{Bookmark, Profile, Status};
use Illuminate\Http\Request;
class BookmarkController extends Controller
@ -16,7 +17,7 @@ class BookmarkController extends Controller
public function store(Request $request)
{
$this->validate($request, [
'item' => 'required|integer|min:1'
'item' => 'required|integer|min:1',
]);
$profile = Auth::user()->profile;
@ -26,11 +27,11 @@ class BookmarkController extends Controller
['status_id' => $status->id], ['profile_id' => $profile->id]
);
if(!$bookmark->wasRecentlyCreated) {
if (!$bookmark->wasRecentlyCreated) {
$bookmark->delete();
}
if($request->ajax()) {
if ($request->ajax()) {
$response = ['code' => 200, 'msg' => 'Bookmark saved!'];
} else {
$response = redirect()->back();
@ -38,5 +39,4 @@ class BookmarkController extends Controller
return $response;
}
}

View file

@ -2,19 +2,21 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Comment;
use App\Jobs\CommentPipeline\CommentPipeline;
use App\Jobs\StatusPipeline\NewStatusPipeline;
use Auth, Hashids;
use App\{Comment, Profile, Status};
use App\Profile;
use App\Status;
use Auth;
use Illuminate\Http\Request;
class CommentController extends Controller
{
public function show(Request $request, $username, int $id, int $cid)
{
$user = Profile::whereUsername($username)->firstOrFail();
$status = Status::whereProfileId($user->id)->whereInReplyToId($id)->findOrFail($cid);
return view('status.reply', compact('user', 'status'));
}
@ -23,15 +25,18 @@ class CommentController extends Controller
$user = Profile::whereUsername($username)->firstOrFail();
$status = Status::whereProfileId($user->id)->findOrFail($id);
$replies = Status::whereInReplyToId($id)->paginate(40);
return view('status.comments', compact('user', 'status', 'replies'));
}
public function store(Request $request)
{
if(Auth::check() === false) { abort(403); }
if (Auth::check() === false) {
abort(403);
}
$this->validate($request, [
'item' => 'required|integer',
'comment' => 'required|string|max:500'
'comment' => 'required|string|max:500',
]);
$comment = $request->input('comment');
$statusId = $request->item;
@ -51,7 +56,7 @@ class CommentController extends Controller
NewStatusPipeline::dispatch($reply, false);
CommentPipeline::dispatch($status, $reply);
if($request->ajax()) {
if ($request->ajax()) {
$response = ['code' => 200, 'msg' => 'Comment saved', 'username' => $profile->username, 'url' => $reply->url(), 'profile' => $profile->url(), 'comment' => $reply->caption];
} else {
$response = redirect($status->url());

View file

@ -2,10 +2,10 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{

View file

@ -2,9 +2,12 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\{Hashtag, Follower, Profile, Status, StatusHashtag};
use App\Follower;
use App\Hashtag;
use App\Profile;
use App\Status;
use Auth;
use Illuminate\Http\Request;
class DiscoverController extends Controller
{
@ -38,7 +41,7 @@ class DiscoverController extends Controller
public function showTags(Request $request, $hashtag)
{
$this->validate($request, [
'page' => 'nullable|integer|min:1|max:10'
'page' => 'nullable|integer|min:1|max:10',
]);
$tag = Hashtag::with('posts')
@ -50,7 +53,7 @@ class DiscoverController extends Controller
->whereIsNsfw(false)
->whereVisibility('public')
->has('media')
->orderBy('id','desc')
->orderBy('id', 'desc')
->simplePaginate(12);
return view('discover.tags.show', compact('tag', 'posts'));

View file

@ -2,25 +2,23 @@
namespace App\Http\Controllers;
use Auth, Cache;
use App\Jobs\InboxPipeline\InboxWorker;
use App\Jobs\RemoteFollowPipeline\RemoteFollowPipeline;
use App\Profile;
use Carbon\Carbon;
use League\Fractal;
use Illuminate\Http\Request;
use App\Transformer\ActivityPub\ProfileOutbox;
use App\Util\Lexer\Nickname;
use App\Util\Webfinger\Webfinger;
use App\Transformer\ActivityPub\{
ProfileOutbox,
ProfileTransformer
};
use App\Jobs\RemoteFollowPipeline\RemoteFollowPipeline;
use App\Jobs\InboxPipeline\InboxWorker;
use Auth;
use Cache;
use Carbon\Carbon;
use Illuminate\Http\Request;
use League\Fractal;
class FederationController extends Controller
{
public function authCheck()
{
if(!Auth::check()) {
if (!Auth::check()) {
return abort(403);
}
}
@ -29,16 +27,18 @@ class FederationController extends Controller
{
$this->authCheck();
$this->validate($request, [
'acct' => 'required|string|min:3|max:255'
'acct' => 'required|string|min:3|max:255',
]);
$acct = $request->input('acct');
$nickname = Nickname::normalizeProfileUrl($acct);
return view('federation.authorizefollow', compact('acct', 'nickname'));
}
public function remoteFollow()
{
$this->authCheck();
return view('federation.remotefollow');
}
@ -46,10 +46,10 @@ class FederationController extends Controller
{
$this->authCheck();
$this->validate($request, [
'url' => 'required|string'
'url' => 'required|string',
]);
if(config('pixelfed.remote_follow_enabled') !== true) {
if (config('pixelfed.remote_follow_enabled') !== true) {
abort(403);
}
@ -67,36 +67,37 @@ class FederationController extends Controller
'links' => [
[
'href' => config('pixelfed.nodeinfo.url'),
'rel' => 'http://nodeinfo.diaspora.software/ns/schema/2.0'
]
]
'rel' => 'http://nodeinfo.diaspora.software/ns/schema/2.0',
],
],
];
return response()->json($res);
}
public function nodeinfo()
{
$res = Cache::remember('api:nodeinfo', 60, function() {
$res = Cache::remember('api:nodeinfo', 60, function () {
return [
'metadata' => [
'nodeName' => config('app.name'),
'software' => [
'homepage' => 'https://pixelfed.org',
'github' => 'https://github.com/pixelfed',
'follow' => 'https://mastodon.social/@pixelfed'
'follow' => 'https://mastodon.social/@pixelfed',
],
],
'openRegistrations' => config('pixelfed.open_registration'),
'protocols' => [
'activitypub'
'activitypub',
],
'services' => [
'inbound' => [],
'outbound' => []
'outbound' => [],
],
'software' => [
'name' => 'pixelfed',
'version' => config('pixelfed.version')
'version' => config('pixelfed.version'),
],
'usage' => [
'localPosts' => \App\Status::whereLocal(true)->whereHas('media')->count(),
@ -105,59 +106,61 @@ class FederationController extends Controller
'total' => \App\User::count(),
'activeHalfyear' => \App\User::where('updated_at', '>', Carbon::now()->subMonths(6)->toDateTimeString())->count(),
'activeMonth' => \App\User::where('updated_at', '>', Carbon::now()->subMonths(1)->toDateTimeString())->count(),
]
],
'version' => '2.0'
],
'version' => '2.0',
];
});
return response()->json($res, 200, [], JSON_PRETTY_PRINT);
}
public function webfinger(Request $request)
{
$this->validate($request, ['resource'=>'required|string|min:3|max:255']);
$hash = hash('sha256', $request->input('resource'));
$webfinger = Cache::remember('api:webfinger:'.$hash, 1440, function() use($request) {
$webfinger = Cache::remember('api:webfinger:'.$hash, 1440, function () use ($request) {
$resource = $request->input('resource');
$parsed = Nickname::normalizeProfileUrl($resource);
$username = $parsed['username'];
$user = Profile::whereUsername($username)->firstOrFail();
return (new Webfinger($user))->generate();
});
return response()->json($webfinger, 200, [], JSON_PRETTY_PRINT);
}
public function userOutbox(Request $request, $username)
{
if(config('pixelfed.activitypub_enabled') == false) {
if (config('pixelfed.activitypub_enabled') == false) {
abort(403);
}
$user = Profile::whereNull('remote_url')->whereUsername($username)->firstOrFail();
$timeline = $user->statuses()->orderBy('created_at','desc')->paginate(10);
$timeline = $user->statuses()->orderBy('created_at', 'desc')->paginate(10);
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Item($user, new ProfileOutbox);
$resource = new Fractal\Resource\Item($user, new ProfileOutbox());
$res = $fractal->createData($resource)->toArray();
return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json');
}
public function userInbox(Request $request, $username)
{
if(config('pixelfed.activitypub_enabled') == false) {
if (config('pixelfed.activitypub_enabled') == false) {
abort(403);
}
$mimes = [
'application/activity+json',
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
];
if(!in_array($request->header('Content-Type'), $mimes)) {
if (!in_array($request->header('Content-Type'), $mimes)) {
abort(500, 'Invalid request');
}
$profile = Profile::whereUsername($username)->firstOrFail();
InboxWorker::dispatch($request, $profile, $request->all());
}
}

View file

@ -2,10 +2,11 @@
namespace App\Http\Controllers;
use Auth;
use App\{Follower, Profile};
use Illuminate\Http\Request;
use App\Follower;
use App\Jobs\FollowPipeline\FollowPipeline;
use App\Profile;
use Auth;
use Illuminate\Http\Request;
class FollowerController extends Controller
{
@ -25,8 +26,8 @@ class FollowerController extends Controller
$isFollowing = Follower::whereProfileId($user->id)->whereFollowingId($target->id)->count();
if($isFollowing == 0) {
$follower = new Follower;
if ($isFollowing == 0) {
$follower = new Follower();
$follower->profile_id = $user->id;
$follower->following_id = $target->id;
$follower->save();
@ -36,7 +37,6 @@ class FollowerController extends Controller
$follower->delete();
}
return redirect()->back();
}
}

View file

@ -2,8 +2,6 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HashtagController extends Controller
{
//

View file

@ -2,8 +2,6 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**

View file

@ -2,10 +2,13 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth, Cache, Hashids;
use App\{Like, Profile, Status, User};
use App\Jobs\LikePipeline\LikePipeline;
use App\Like;
use App\Status;
use App\User;
use Auth;
use Cache;
use Illuminate\Http\Request;
class LikeController extends Controller
{
@ -25,12 +28,12 @@ class LikeController extends Controller
$count = $status->likes_count;
if($status->likes()->whereProfileId($profile->id)->count() !== 0) {
if ($status->likes()->whereProfileId($profile->id)->count() !== 0) {
$like = Like::whereProfileId($profile->id)->whereStatusId($status->id)->firstOrFail();
$like->forceDelete();
$count--;
} else {
$like = new Like;
$like = new Like();
$like->profile_id = $profile->id;
$like->status_id = $status->id;
$like->save();
@ -45,7 +48,7 @@ class LikeController extends Controller
Cache::put('api:like-ids:user:'.$profile->id, $likes, 1440);
if($request->ajax()) {
if ($request->ajax()) {
$response = ['code' => 200, 'msg' => 'Like saved', 'count' => $count];
} else {
$response = redirect($status->url());

View file

@ -2,8 +2,6 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MediaController extends Controller
{
//

View file

@ -2,8 +2,6 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class NotificationController extends Controller
{
//

View file

@ -2,36 +2,33 @@
namespace App\Http\Controllers;
use App\Follower;
use App\Profile;
use App\Transformer\ActivityPub\ProfileTransformer;
use App\User;
use Auth;
use Illuminate\Http\Request;
use Auth, Cache;
use App\{Follower, Profile, User};
use League\Fractal;
use App\Util\Lexer\Nickname;
use App\Util\Webfinger\Webfinger;
use App\Transformer\ActivityPub\{
ProfileOutbox,
ProfileTransformer
};
class ProfileController extends Controller
{
public function show(Request $request, $username)
{
$user = Profile::whereUsername($username)->firstOrFail();
if($user->remote_url) {
$settings = new \StdClass;
if ($user->remote_url) {
$settings = new \StdClass();
$settings->crawlable = false;
} else {
$settings = User::whereUsername($username)->firstOrFail()->settings;
}
if($request->wantsJson() && config('pixelfed.activitypub_enabled')) {
if ($request->wantsJson() && config('pixelfed.activitypub_enabled')) {
return $this->showActivityPub($request, $user);
}
if($user->is_private == true) {
if ($user->is_private == true) {
$can_access = $this->privateProfileCheck($user);
if($can_access !== true) {
if ($can_access !== true) {
abort(403);
}
}
@ -43,7 +40,7 @@ class ProfileController extends Controller
->whereHas('media')
->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
->orderBy('created_at','desc')
->orderBy('created_at', 'desc')
->withCount(['comments', 'likes'])
->simplePaginate(21);
@ -55,7 +52,7 @@ class ProfileController extends Controller
$user = Profile::whereUsername($username)->firstOrFail();
$settings = User::whereUsername($username)->firstOrFail()->settings;
if($request->wantsJson() && config('pixelfed.activitypub_enabled')) {
if ($request->wantsJson() && config('pixelfed.activitypub_enabled')) {
return $this->showActivityPub($request, $user);
}
@ -64,13 +61,13 @@ class ProfileController extends Controller
protected function privateProfileCheck(Profile $profile)
{
if(Auth::check() === false) {
if (Auth::check() === false) {
return false;
}
$follower_ids = (array) $profile->followers()->pluck('followers.profile_id');
$pid = Auth::user()->profile->id;
if(!in_array($pid, $follower_ids) && $pid !== $profile->id) {
if (!in_array($pid, $follower_ids) && $pid !== $profile->id) {
return false;
}
@ -80,8 +77,9 @@ class ProfileController extends Controller
public function showActivityPub(Request $request, $user)
{
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Item($user, new ProfileTransformer);
$resource = new Fractal\Resource\Item($user, new ProfileTransformer());
$res = $fractal->createData($resource)->toArray();
return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json');
}
@ -89,6 +87,7 @@ class ProfileController extends Controller
{
$profile = Profile::whereUsername($user)->firstOrFail();
$items = $profile->statuses()->orderBy('created_at', 'desc')->take(10)->get();
return response()->view('atom.user', compact('profile', 'items'))
->header('Content-Type', 'application/atom+xml');
}
@ -100,8 +99,9 @@ class ProfileController extends Controller
$user = $profile;
$owner = Auth::check() && Auth::id() === $user->user_id;
$is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
$followers = $profile->followers()->orderBy('created_at','desc')->simplePaginate(12);
$followers = $profile->followers()->orderBy('created_at', 'desc')->simplePaginate(12);
$is_admin = is_null($user->domain) ? $user->user->is_admin : false;
return view('profile.followers', compact('user', 'profile', 'followers', 'owner', 'is_following', 'is_admin'));
}
@ -112,23 +112,25 @@ class ProfileController extends Controller
$user = $profile;
$owner = Auth::check() && Auth::id() === $user->user_id;
$is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
$following = $profile->following()->orderBy('created_at','desc')->simplePaginate(12);
$following = $profile->following()->orderBy('created_at', 'desc')->simplePaginate(12);
$is_admin = is_null($user->domain) ? $user->user->is_admin : false;
return view('profile.following', compact('user', 'profile', 'following', 'owner', 'is_following', 'is_admin'));
}
public function savedBookmarks(Request $request, $username)
{
if(Auth::check() === false || $username !== Auth::user()->username) {
if (Auth::check() === false || $username !== Auth::user()->username) {
abort(403);
}
$user = Auth::user()->profile;
$settings = User::whereUsername($username)->firstOrFail()->settings;
$owner = true;
$following = false;
$timeline = $user->bookmarks()->withCount(['likes','comments'])->orderBy('created_at','desc')->simplePaginate(10);
$timeline = $user->bookmarks()->withCount(['likes', 'comments'])->orderBy('created_at', 'desc')->simplePaginate(10);
$is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
$is_admin = is_null($user->domain) ? $user->user->is_admin : false;
return view('profile.show', compact('user', 'settings', 'owner', 'following', 'timeline', 'is_following', 'is_admin'));
}
}

View file

@ -2,9 +2,12 @@
namespace App\Http\Controllers;
use App\Profile;
use App\Report;
use App\Status;
use App\User;
use Auth;
use Illuminate\Http\Request;
use App\{Avatar, Profile, Report, Status, User};
class ReportController extends Controller
{
@ -19,8 +22,9 @@ class ReportController extends Controller
{
$this->validate($request, [
'type' => 'required|alpha_dash',
'id' => 'required|integer|min:1'
'id' => 'required|integer|min:1',
]);
return view('report.form');
}
@ -85,7 +89,7 @@ class ReportController extends Controller
'report' => 'required|alpha_dash',
'type' => 'required|alpha_dash',
'id' => 'required|integer|min:1',
'msg' => 'nullable|string|max:150'
'msg' => 'nullable|string|max:150',
]);
$profile = Auth::user()->profile;
@ -96,7 +100,7 @@ class ReportController extends Controller
$object = null;
$types = ['spam', 'sensitive', 'abusive'];
if(!in_array($reportType, $types)) {
if (!in_array($reportType, $types)) {
return redirect('/timeline')->with('error', 'Invalid report type');
}
@ -115,15 +119,15 @@ class ReportController extends Controller
break;
}
if($exists !== 0) {
if ($exists !== 0) {
return redirect('/timeline')->with('error', 'You have already reported this!');
}
if($object->profile_id == $profile->id) {
if ($object->profile_id == $profile->id) {
return redirect('/timeline')->with('error', 'You cannot report your own content!');
}
$report = new Report;
$report = new Report();
$report->profile_id = $profile->id;
$report->user_id = Auth::id();
$report->object_id = $object->id;
@ -135,5 +139,4 @@ class ReportController extends Controller
return redirect('/timeline')->with('status', 'Report successfully sent!');
}
}

View file

@ -2,7 +2,8 @@
namespace App\Http\Controllers;
use App\{Hashtag, Profile};
use App\Hashtag;
use App\Profile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
@ -10,30 +11,31 @@ class SearchController extends Controller
{
public function searchAPI(Request $request, $tag)
{
$res = Cache::remember('api:search:tag:' . $tag, 1440, function() use($tag) {
$res = Cache::remember('api:search:tag:'.$tag, 1440, function () use ($tag) {
$res = Hashtag::where('slug', 'like', '%'.$tag.'%')->get();
$tags = $res->map(function($item, $key) {
$tags = $res->map(function ($item, $key) {
return [
'count' => $item->posts()->count(),
'url' => $item->url(),
'type' => 'hashtag',
'value' => $item->name,
'tokens' => explode('-', $item->name),
'name' => null
'name' => null,
];
});
$res = Profile::where('username', 'like', '%'.$tag.'%')->get();
$profiles = $res->map(function($item, $key) {
$profiles = $res->map(function ($item, $key) {
return [
'count' => 0,
'url' => $item->url(),
'type' => 'profile',
'value' => $item->username,
'tokens' => [$item->username],
'name' => $item->name
'name' => $item->name,
];
});
$tags = $tags->push($profiles[0]);
return $tags;
});

View file

@ -2,10 +2,15 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\{AccountLog, EmailVerification, Media, Profile, User};
use Auth, DB;
use App\AccountLog;
use App\EmailVerification;
use App\Media;
use App\Profile;
use App\User;
use App\Util\Lexer\PrettyNumber;
use Auth;
use DB;
use Illuminate\Http\Request;
class SettingsController extends Controller
{
@ -24,16 +29,17 @@ class SettingsController extends Controller
$storage['percentUsed'] = ceil($storage['used'] / $storage['limit'] * 100);
$storage['limitPretty'] = PrettyNumber::size($storage['limit']);
$storage['usedPretty'] = PrettyNumber::size($storage['used']);
return view('settings.home', compact('storage'));
}
public function homeUpdate(Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:' . config('pixelfed.max_name_length'),
'bio' => 'nullable|string|max:' . config('pixelfed.max_bio_length'),
'name' => 'required|string|max:'.config('pixelfed.max_name_length'),
'bio' => 'nullable|string|max:'.config('pixelfed.max_bio_length'),
'website' => 'nullable|url',
'email' => 'nullable|email'
'email' => 'nullable|email',
]);
$changes = false;
@ -46,11 +52,11 @@ class SettingsController extends Controller
$validate = config('pixelfed.enforce_email_verification');
if($user->email != $email) {
if ($user->email != $email) {
$changes = true;
$user->email = $email;
if($validate) {
if ($validate) {
$user->email_verified_at = null;
// Prevent old verifications from working
EmailVerification::whereUserId($user->id)->delete();
@ -58,27 +64,28 @@ class SettingsController extends Controller
}
// Only allow email to be updated if not yet verified
if(!$validate || !$changes && $user->email_verified_at) {
if($profile->name != $name) {
if (!$validate || !$changes && $user->email_verified_at) {
if ($profile->name != $name) {
$changes = true;
$user->name = $name;
$profile->name = $name;
}
if(!$profile->website || $profile->website != $website) {
if (!$profile->website || $profile->website != $website) {
$changes = true;
$profile->website = $website;
}
if(!$profile->bio || !$profile->bio != $bio) {
if (!$profile->bio || !$profile->bio != $bio) {
$changes = true;
$profile->bio = $bio;
}
}
if($changes === true) {
if ($changes === true) {
$user->save();
$profile->save();
return redirect('/settings/home')->with('status', 'Profile successfully updated!');
}
@ -104,12 +111,13 @@ class SettingsController extends Controller
$user = Auth::user();
if(password_verify($current, $user->password) && $new === $confirm) {
if (password_verify($current, $user->password) && $new === $confirm) {
$user->password = bcrypt($new);
$user->save();
return redirect('/settings/home')->with('status', 'Password successfully updated!');
}
return redirect('/settings/home')->with('error', 'There was an error with your request!');
}
@ -126,6 +134,7 @@ class SettingsController extends Controller
public function accessibility()
{
$settings = Auth::user()->settings;
return view('settings.accessibility', compact('settings'));
}
@ -137,17 +146,18 @@ class SettingsController extends Controller
'reduce_motion',
'optimize_screen_reader',
'high_contrast_mode',
'video_autoplay'
'video_autoplay',
];
foreach($fields as $field) {
foreach ($fields as $field) {
$form = $request->input($field);
if($form == 'on') {
if ($form == 'on') {
$settings->{$field} = true;
} else {
$settings->{$field} = false;
}
$settings->save();
}
return redirect(route('settings.accessibility'))->with('status', 'Settings successfully updated!');
}
@ -161,6 +171,7 @@ class SettingsController extends Controller
$settings = Auth::user()->settings;
$is_private = Auth::user()->profile->is_private;
$settings['is_private'] = (bool) $is_private;
return view('settings.privacy', compact('settings'));
}
@ -172,12 +183,12 @@ class SettingsController extends Controller
'is_private',
'crawlable',
'show_profile_follower_count',
'show_profile_following_count'
'show_profile_following_count',
];
foreach($fields as $field) {
foreach ($fields as $field) {
$form = $request->input($field);
if($field == 'is_private') {
if($form == 'on') {
if ($field == 'is_private') {
if ($form == 'on') {
$profile->{$field} = true;
$settings->show_guests = false;
$settings->show_discover = false;
@ -186,14 +197,14 @@ class SettingsController extends Controller
$profile->{$field} = false;
$profile->save();
}
} elseif($field == 'crawlable') {
if($form == 'on') {
} elseif ($field == 'crawlable') {
if ($form == 'on') {
$settings->{$field} = false;
} else {
$settings->{$field} = true;
}
} else {
if($form == 'on') {
if ($form == 'on') {
$settings->{$field} = true;
} else {
$settings->{$field} = false;
@ -201,6 +212,7 @@ class SettingsController extends Controller
}
$settings->save();
}
return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!');
}
@ -211,9 +223,10 @@ class SettingsController extends Controller
->limit(20)
->get();
$activity = AccountLog::whereUserId(Auth::id())
->orderBy('created_at','desc')
->orderBy('created_at', 'desc')
->limit(50)
->get();
return view('settings.security', compact('sessions', 'activity'));
}

View file

@ -2,17 +2,21 @@
namespace App\Http\Controllers;
use App, Auth, Cache;
use Illuminate\Http\Request;
use App\{Follower, Profile, Status, User};
use App;
use App\Follower;
use App\Profile;
use App\Status;
use App\User;
use App\Util\Lexer\PrettyNumber;
use Auth;
use Cache;
use Illuminate\Http\Request;
class SiteController extends Controller
{
public function home()
{
if(Auth::check()) {
if (Auth::check()) {
return $this->homeTimeline();
} else {
return $this->homeGuest();
@ -31,25 +35,27 @@ class SiteController extends Controller
$following->push(Auth::user()->profile->id);
$timeline = Status::whereIn('profile_id', $following)
->whereHas('media')
->orderBy('id','desc')
->orderBy('id', 'desc')
->withCount(['comments', 'likes', 'shares'])
->simplePaginate(20);
$type = 'personal';
return view('timeline.template', compact('timeline', 'type'));
}
public function changeLocale(Request $request, $locale)
{
if(!App::isLocale($locale)) {
if (!App::isLocale($locale)) {
return redirect()->back();
}
App::setLocale($locale);
return redirect()->back();
}
public function about()
{
$res = Cache::remember('site:page:about', 15, function() {
$res = Cache::remember('site:page:about', 15, function () {
$statuses = Status::whereHas('media')
->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
@ -58,8 +64,10 @@ class SiteController extends Controller
$userCount = PrettyNumber::convert(User::count());
$remoteCount = PrettyNumber::convert(Profile::whereNotNull('remote_url')->count());
$adminContact = User::whereIsAdmin(true)->first();
return view('site.about')->with(compact('statusCount', 'userCount', 'remoteCount', 'adminContact'))->render();
});
return $res;
}
}

View file

@ -2,14 +2,18 @@
namespace App\Http\Controllers;
use Auth, Cache;
use League\Fractal;
use Illuminate\Http\Request;
use Vinkla\Hashids\Facades\Hashids;
use App\{Media, Profile, Status, User};
use App\Jobs\ImageOptimizePipeline\ImageOptimize;
use App\Jobs\StatusPipeline\NewStatusPipeline;
use App\Jobs\StatusPipeline\StatusDelete;
use App\Media;
use App\Profile;
use App\Status;
use App\Transformer\ActivityPub\StatusTransformer;
use App\Jobs\StatusPipeline\{NewStatusPipeline, StatusDelete};
use App\User;
use Auth;
use Cache;
use Illuminate\Http\Request;
use League\Fractal;
class StatusController extends Controller
{
@ -21,7 +25,7 @@ class StatusController extends Controller
->withCount(['likes', 'comments', 'media'])
->findOrFail($id);
if($request->wantsJson() && config('pixelfed.activitypub_enabled')) {
if ($request->wantsJson() && config('pixelfed.activitypub_enabled')) {
return $this->showActivityPub($request, $status);
}
@ -34,25 +38,28 @@ class StatusController extends Controller
protected function detectTemplate($status)
{
$template = Cache::rememberForever('template:status:type:'.$status->id, function () use($status) {
$template = Cache::rememberForever('template:status:type:'.$status->id, function () use ($status) {
$template = 'status.show.photo';
if(!$status->media_path && $status->in_reply_to_id) {
if (!$status->media_path && $status->in_reply_to_id) {
$template = 'status.reply';
}
if($status->media->count() > 1) {
if ($status->media->count() > 1) {
$template = 'status.show.album';
}
if($status->viewType() == 'video') {
if ($status->viewType() == 'video') {
$template = 'status.show.video';
}
return $template;
});
return $template;
}
public function compose()
{
$this->authCheck();
return view('status.compose');
}
@ -63,27 +70,27 @@ class StatusController extends Controller
$size = Media::whereUserId($user->id)->sum('size') / 1000;
$limit = (int) config('pixelfed.max_account_size');
if($size >= $limit) {
if ($size >= $limit) {
return redirect()->back()->with('error', 'You have exceeded your storage limit. Please click <a href="#">here</a> for more info.');
}
$this->validate($request, [
'photo.*' => 'required|mimes:jpeg,png,gif|max:' . config('pixelfed.max_photo_size'),
'caption' => 'string|max:' . config('pixelfed.max_caption_length'),
'photo.*' => 'required|mimes:jpeg,png,gif|max:'.config('pixelfed.max_photo_size'),
'caption' => 'string|max:'.config('pixelfed.max_caption_length'),
'cw' => 'nullable|string',
'filter_class' => 'nullable|string',
'filter_name' => 'nullable|string',
]);
if(count($request->file('photo')) > config('pixelfed.max_album_length')) {
return redirect()->back()->with('error', 'Too many files, max limit per post: ' . config('pixelfed.max_album_length'));
if (count($request->file('photo')) > config('pixelfed.max_album_length')) {
return redirect()->back()->with('error', 'Too many files, max limit per post: '.config('pixelfed.max_album_length'));
}
$cw = $request->filled('cw') && $request->cw == 'on' ? true : false;
$monthHash = hash('sha1', date('Y') . date('m'));
$userHash = hash('sha1', $user->id . (string) $user->created_at);
$monthHash = hash('sha1', date('Y').date('m'));
$userHash = hash('sha1', $user->id.(string) $user->created_at);
$profile = $user->profile;
$status = new Status;
$status = new Status();
$status->profile_id = $profile->id;
$status->caption = strip_tags($request->caption);
$status->is_nsfw = $cw;
@ -96,7 +103,7 @@ class StatusController extends Controller
$storagePath = "public/m/{$monthHash}/{$userHash}";
$path = $v->store($storagePath);
$hash = \hash_file('sha256', $v);
$media = new Media;
$media = new Media();
$media->status_id = $status->id;
$media->profile_id = $profile->id;
$media->user_id = $user->id;
@ -121,18 +128,18 @@ class StatusController extends Controller
public function delete(Request $request)
{
if(!Auth::check()) {
if (!Auth::check()) {
abort(403);
}
$this->validate($request, [
'type' => 'required|string',
'item' => 'required|integer|min:1'
'item' => 'required|integer|min:1',
]);
$status = Status::findOrFail($request->input('item'));
if($status->profile_id === Auth::user()->profile->id || Auth::user()->is_admin == true) {
if ($status->profile_id === Auth::user()->profile->id || Auth::user()->is_admin == true) {
StatusDelete::dispatch($status);
}
@ -153,23 +160,23 @@ class StatusController extends Controller
$exists = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)
->count();
if($exists !== 0) {
if ($exists !== 0) {
$shares = Status::whereProfileId(Auth::user()->profile->id)
->whereReblogOfId($status->id)
->get();
foreach($shares as $share) {
foreach ($shares as $share) {
$share->delete();
$count--;
}
} else {
$share = new Status;
$share = new Status();
$share->profile_id = $profile->id;
$share->reblog_of_id = $status->id;
$share->save();
$count++;
}
if($request->ajax()) {
if ($request->ajax()) {
$response = ['code' => 200, 'msg' => 'Share saved', 'count' => $count];
} else {
$response = redirect($status->url());
@ -181,8 +188,9 @@ class StatusController extends Controller
public function showActivityPub(Request $request, $status)
{
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Item($status, new StatusTransformer);
$resource = new Fractal\Resource\Item($status, new StatusTransformer());
$res = $fractal->createData($resource)->toArray();
return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json');
}
@ -193,10 +201,10 @@ class StatusController extends Controller
$status = Status::whereProfileId($user->id)
->with(['media'])
->findOrFail($id);
return view('status.edit', compact('user', 'status'));
}
public function editStore(Request $request, $username, $id)
{
$this->authCheck();
@ -208,7 +216,7 @@ class StatusController extends Controller
$this->validate($request, [
'id' => 'required|integer|min:1',
'caption' => 'nullable',
'filter' => 'nullable|alpha_dash|max:30'
'filter' => 'nullable|alpha_dash|max:30',
]);
$id = $request->input('id');
@ -221,26 +229,26 @@ class StatusController extends Controller
$changed = false;
if($media->caption != $caption) {
if ($media->caption != $caption) {
$media->caption = $caption;
$changed = true;
}
if($media->filter_class != $filter) {
if ($media->filter_class != $filter) {
$media->filter_class = $filter;
$changed = true;
}
if($changed === true) {
if ($changed === true) {
$media->save();
}
return response()->json([], 200);
}
protected function authCheck()
{
if(Auth::check() == false)
{
if (Auth::check() == false) {
abort(403);
}
}

View file

@ -2,10 +2,6 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Profile;
class StoryController extends Controller
{
}

View file

@ -2,9 +2,12 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Follower;
use App\Profile;
use App\Status;
use App\User;
use App\UserFilter;
use Auth;
use App\{Follower, Profile, Status, User, UserFilter};
class TimelineController extends Controller
{
@ -25,10 +28,11 @@ class TimelineController extends Controller
->pluck('filterable_id');
$timeline = Status::whereIn('profile_id', $following)
->whereNotIn('profile_id', $filtered)
->orderBy('id','desc')
->orderBy('id', 'desc')
->withCount(['comments', 'likes'])
->simplePaginate(20);
$type = 'personal';
return view('timeline.template', compact('timeline', 'type'));
}
@ -49,10 +53,10 @@ class TimelineController extends Controller
->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
->withCount(['comments', 'likes'])
->orderBy('id','desc')
->orderBy('id', 'desc')
->simplePaginate(20);
$type = 'local';
return view('timeline.template', compact('timeline', 'type'));
}
}

View file

@ -2,7 +2,8 @@
namespace App\Http\Middleware;
use Auth, Closure;
use Auth;
use Closure;
class Admin
{
@ -11,11 +12,12 @@ class Admin
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if(Auth::check() == false || Auth::user()->is_admin == false) {
if (Auth::check() == false || Auth::user()->is_admin == false) {
return redirect(config('app.url'));
}

View file

@ -2,7 +2,7 @@
namespace App\Http\Middleware;
use Auth, Closure;
use Closure;
class EmailVerificationCheck
{
@ -11,17 +11,19 @@ class EmailVerificationCheck
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if($request->user() &&
if ($request->user() &&
config('pixelfed.enforce_email_verification') &&
is_null($request->user()->email_verified_at) &&
!$request->is('i/verify-email', 'log*', 'i/confirm-email/*', 'settings/home')
) {
return redirect('/i/verify-email');
}
return $next($request);
}
}

View file

@ -13,6 +13,7 @@ class RedirectIfAuthenticated
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
*
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)

View file

@ -2,8 +2,8 @@
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{

View file

@ -2,14 +2,15 @@
namespace App\Jobs\AvatarPipeline;
use \Carbon\Carbon;
use Image as Intervention;
use App\{Avatar, Profile};
use App\Avatar;
use App\Profile;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Image as Intervention;
class AvatarOptimize implements ShouldQueue
{
@ -54,16 +55,15 @@ class AvatarOptimize implements ShouldQueue
$avatar->save();
$this->deleteOldAvatar($avatar->media_path, $this->current);
} catch (Exception $e) {
}
}
protected function deleteOldAvatar($new, $current)
{
if(storage_path('app/' . $new) == $current) {
if (storage_path('app/'.$new) == $current) {
return;
}
if(is_file($current)) {
if (is_file($current)) {
@unlink($current);
}
}

View file

@ -2,23 +2,24 @@
namespace App\Jobs\AvatarPipeline;
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;
use Illuminate\Support\Str;
use Bitverse\Identicon\Identicon;
use App\Avatar;
use App\Profile;
use App\Util\Identicon\Preprocessor\HashPreprocessor;
use Bitverse\Identicon\Color\Color;
use Bitverse\Identicon\Generator\RingsGenerator;
use App\Util\Identicon\Preprocessor\HashPreprocessor;
use Bitverse\Identicon\Identicon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class CreateAvatar implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $profile;
/**
* Create a new job instance.
*
@ -44,66 +45,63 @@ class CreateAvatar implements ShouldQueue
$identicon = new Identicon(new HashPreprocessor('sha256'), $generator);
$hash = $username . str_random(12);
$hash = $username.str_random(12);
$icon = $identicon->getIcon($hash);
try {
$baseDir = storage_path('app/public/avatars');
if(!is_dir($baseDir)) {
if (!is_dir($baseDir)) {
mkdir($baseDir);
}
$prefix = $profile->id;
$padded = str_pad($prefix, 12, 0, STR_PAD_LEFT);
$parts = str_split($padded, 3);
foreach($parts as $k => $part) {
if($k == 0) {
foreach ($parts as $k => $part) {
if ($k == 0) {
$prefix = storage_path('app/public/avatars/'.$parts[0]);
if(!is_dir($prefix)) {
if (!is_dir($prefix)) {
mkdir($prefix);
}
}
if($k == 1) {
if ($k == 1) {
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1]);
if(!is_dir($prefix)) {
if (!is_dir($prefix)) {
mkdir($prefix);
}
}
if($k == 2) {
if ($k == 2) {
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2]);
if(!is_dir($prefix)) {
if (!is_dir($prefix)) {
mkdir($prefix);
}
}
if($k == 3) {
if ($k == 3) {
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3];
$prefix = storage_path('app/'.$avatarpath);
if(!is_dir($prefix)) {
if (!is_dir($prefix)) {
mkdir($prefix);
}
}
}
$dir = storage_path('app/'.$avatarpath);
//$dir = storage_path('app/public/avatars/'.$prefix);
if(!is_dir($dir)) {
if (!is_dir($dir)) {
mkdir($dir);
}
//$path = 'public/avatars/' . $prefix . '/avatar.svg';
$path = $avatarpath . '/avatar.svg';
$basePath = storage_path('app/' . $path);
$path = $avatarpath.'/avatar.svg';
$basePath = storage_path('app/'.$path);
file_put_contents($basePath, $icon);
} catch (Exception $e) {
}
$avatar = new Avatar;
$avatar = new Avatar();
$avatar->profile_id = $profile->id;
$avatar->media_path = $path;
$avatar->thumb_path = $path;
$avatar->change_count = 0;
$avatar->last_processed_at = \Carbon\Carbon::now();
$avatar->save();
}
}

View file

@ -2,14 +2,16 @@
namespace App\Jobs\CommentPipeline;
use Cache, Log, Redis;
use App\{Like, Notification, Status};
use App\Util\Lexer\Hashtag as HashtagLexer;
use App\Notification;
use App\Status;
use Cache;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
use Redis;
class CommentPipeline implements ShouldQueue
{
@ -42,13 +44,12 @@ class CommentPipeline implements ShouldQueue
$target = $status->profile;
$actor = $comment->profile;
if($actor->id === $target->id) {
if ($actor->id === $target->id) {
return true;
}
try {
$notification = new Notification;
$notification = new Notification();
$notification->profile_id = $target->id;
$notification->actor_id = $actor->id;
$notification->action = 'comment';
@ -58,16 +59,14 @@ class CommentPipeline implements ShouldQueue
$notification->item_type = "App\Status";
$notification->save();
Cache::forever('notification.' . $notification->id, $notification);
Cache::forever('notification.'.$notification->id, $notification);
$redis = Redis::connection();
$nkey = config('cache.prefix').':user.' . $target->id . '.notifications';
$nkey = config('cache.prefix').':user.'.$target->id.'.notifications';
$redis->lpush($nkey, $notification->id);
} catch (Exception $e) {
Log::error($e);
}
}
}

View file

@ -2,14 +2,15 @@
namespace App\Jobs\FollowPipeline;
use Cache, Log, Redis;
use App\{Like, Notification};
use App\Notification;
use Cache;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Jobs\FollowPipeline\FollowDiscover;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
use Redis;
class FollowPipeline implements ShouldQueue
{
@ -39,8 +40,7 @@ class FollowPipeline implements ShouldQueue
$target = $follower->target;
try {
$notification = new Notification;
$notification = new Notification();
$notification->profile_id = $target->id;
$notification->actor_id = $actor->id;
$notification->action = 'follow';
@ -50,13 +50,12 @@ class FollowPipeline implements ShouldQueue
$notification->item_type = "App\Profile";
$notification->save();
Cache::forever('notification.' . $notification->id, $notification);
Cache::forever('notification.'.$notification->id, $notification);
$redis = Redis::connection();
$nkey = config('cache.prefix').':user.' . $target->id . '.notifications';
$nkey = config('cache.prefix').':user.'.$target->id.'.notifications';
$redis->lpush($nkey, $notification->id);
} catch (Exception $e) {
Log::error($e);
}

View file

@ -2,14 +2,12 @@
namespace App\Jobs\ImageOptimizePipeline;
use Carbon\Carbon;
use ImageOptimizer;
use App\{Media, Status};
use App\Media;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ImageOptimize implements ShouldQueue
{
@ -35,8 +33,8 @@ class ImageOptimize implements ShouldQueue
public function handle()
{
$media = $this->media;
$path = storage_path('app/'. $media->media_path);
if(!is_file($path)) {
$path = storage_path('app/'.$media->media_path);
if (!is_file($path)) {
return;
}

View file

@ -2,15 +2,13 @@
namespace App\Jobs\ImageOptimizePipeline;
use Carbon\Carbon;
use ImageOptimizer;
use App\{Media, Status};
use App\Media;
use App\Util\Media\Image;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ImageResize implements ShouldQueue
{
@ -36,16 +34,15 @@ class ImageResize implements ShouldQueue
public function handle()
{
$media = $this->media;
$path = storage_path('app/'. $media->media_path);
if(!is_file($path)) {
$path = storage_path('app/'.$media->media_path);
if (!is_file($path)) {
return;
}
try {
$img = new Image;
$img = new Image();
$img->resizeImage($media);
} catch (Exception $e) {
}
ImageThumbnail::dispatch($media);

View file

@ -2,14 +2,14 @@
namespace App\Jobs\ImageOptimizePipeline;
use Carbon\Carbon;
use App\{Media, Status};
use App\Media;
use App\Util\Media\Image;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ImageThumbnail implements ShouldQueue
{
@ -35,16 +35,15 @@ class ImageThumbnail implements ShouldQueue
public function handle()
{
$media = $this->media;
$path = storage_path('app/'. $media->media_path);
if(!is_file($path)) {
$path = storage_path('app/'.$media->media_path);
if (!is_file($path)) {
return;
}
try {
$img = new Image;
$img = new Image();
$img->resizeThumbnail($media);
} catch (Exception $e) {
}
$media->processed_at = Carbon::now();

View file

@ -2,13 +2,13 @@
namespace App\Jobs\ImageOptimizePipeline;
use ImageOptimizer;
use App\{Media, Status};
use App\Media;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use ImageOptimizer;
class ImageUpdate implements ShouldQueue
{
@ -19,7 +19,7 @@ class ImageUpdate implements ShouldQueue
protected $protectedMimes = [
'image/gif',
'image/bmp',
'video/mp4'
'video/mp4',
];
/**
@ -40,18 +40,18 @@ class ImageUpdate implements ShouldQueue
public function handle()
{
$media = $this->media;
$path = storage_path('app/'. $media->media_path);
$thumb = storage_path('app/'. $media->thumbnail_path);
$path = storage_path('app/'.$media->media_path);
$thumb = storage_path('app/'.$media->thumbnail_path);
try {
if(!in_array($media->mime, $this->protectedMimes))
{
if (!in_array($media->mime, $this->protectedMimes)) {
ImageOptimizer::optimize($thumb);
ImageOptimizer::optimize($path);
}
} catch (Exception $e) {
return;
}
if(!is_file($path) || !is_file($thumb)) {
if (!is_file($path) || !is_file($thumb)) {
return;
}
$photo_size = filesize($path);

View file

@ -5,10 +5,10 @@ namespace App\Jobs\InboxPipeline;
use App\Profile;
use App\Util\ActivityPub\Inbox;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class InboxWorker implements ShouldQueue
{
@ -39,5 +39,4 @@ class InboxWorker implements ShouldQueue
{
(new Inbox($this->request, $this->profile, $this->payload))->handle();
}
}

View file

@ -2,13 +2,12 @@
namespace App\Jobs\InboxPipeline;
use App\Profile;
use App\Util\ActivityPub\Inbox;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SharedInboxWorker implements ShouldQueue
{

View file

@ -2,19 +2,23 @@
namespace App\Jobs\LikePipeline;
use Cache, Log, Redis;
use App\{Like, Notification};
use App\Like;
use App\Notification;
use Cache;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
use Redis;
class LikePipeline implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $like;
/**
* Create a new job instance.
*
@ -37,7 +41,7 @@ class LikePipeline implements ShouldQueue
$status = $this->like->status;
$actor = $this->like->actor;
if($status->url !== null) {
if ($status->url !== null) {
// Ignore notifications to remote statuses
return;
}
@ -49,13 +53,12 @@ class LikePipeline implements ShouldQueue
->whereItemType('App\Status')
->count();
if($actor->id === $status->profile_id || $exists !== 0) {
if ($actor->id === $status->profile_id || $exists !== 0) {
return true;
}
try {
$notification = new Notification;
$notification = new Notification();
$notification->profile_id = $status->profile_id;
$notification->actor_id = $actor->id;
$notification->action = 'like';
@ -65,12 +68,11 @@ class LikePipeline implements ShouldQueue
$notification->item_type = "App\Status";
$notification->save();
Cache::forever('notification.' . $notification->id, $notification);
Cache::forever('notification.'.$notification->id, $notification);
$redis = Redis::connection();
$key = config('cache.prefix').':user.' . $status->profile_id . '.notifications';
$key = config('cache.prefix').':user.'.$status->profile_id.'.notifications';
$redis->lpush($key, $notification->id);
} catch (Exception $e) {
Log::error($e);
}

View file

@ -2,13 +2,14 @@
namespace App\Jobs\MentionPipeline;
use Cache, Log, Redis;
use App\{Mention, Notification, Profile, Status};
use App\Mention;
use App\Notification;
use App\Status;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class MentionPipeline implements ShouldQueue
{
@ -35,7 +36,6 @@ class MentionPipeline implements ShouldQueue
*/
public function handle()
{
$status = $this->status;
$mention = $this->mention;
$actor = $this->status->profile;
@ -48,13 +48,12 @@ class MentionPipeline implements ShouldQueue
->whereItemType('App\Status')
->count();
if($actor->id === $target || $exists !== 0) {
if ($actor->id === $target || $exists !== 0) {
return true;
}
try {
$notification = new Notification;
$notification = new Notification();
$notification->profile_id = $target;
$notification->actor_id = $actor->id;
$notification->action = 'mention';
@ -63,10 +62,7 @@ class MentionPipeline implements ShouldQueue
$notification->item_id = $status->id;
$notification->item_type = "App\Status";
$notification->save();
} catch (Exception $e) {
}
}
}

View file

@ -2,18 +2,20 @@
namespace App\Jobs\RemoteFollowPipeline;
use Zttp\Zttp;
use Log, Storage;
use App\Jobs\ImageOptimizePipeline\ImageThumbnail;
use App\Jobs\StatusPipeline\NewStatusPipeline;
use App\Media;
use App\Status;
use Carbon\Carbon;
use Illuminate\Http\File;
use App\{Media, Profile, Status};
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Jobs\StatusPipeline\NewStatusPipeline;
use App\Jobs\ImageOptimizePipeline\ImageThumbnail;
use Illuminate\Http\File;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
use Storage;
use Zttp\Zttp;
class RemoteFollowImportRecent implements ShouldQueue
{
@ -42,7 +44,7 @@ class RemoteFollowImportRecent implements ShouldQueue
'image/jpg',
'image/jpeg',
'image/png',
'image/gif'
'image/gif',
];
}
@ -62,7 +64,7 @@ class RemoteFollowImportRecent implements ShouldQueue
$url = ($url == false) ? $this->actor['outbox'] : $url;
$response = Zttp::withHeaders([
'User-Agent' => 'PixelFedBot v0.1 - https://pixelfed.org'
'User-Agent' => 'PixelFedBot v0.1 - https://pixelfed.org',
])->get($url);
$this->outbox = $response->json();
@ -73,13 +75,14 @@ class RemoteFollowImportRecent implements ShouldQueue
{
$types = ['OrderedCollection', 'OrderedCollectionPage'];
if(isset($outbox['totalItems']) && $outbox['totalItems'] < 1) {
if (isset($outbox['totalItems']) && $outbox['totalItems'] < 1) {
// Skip remote fetch, not enough posts
Log::info('not enough items');
return;
}
if(isset($outbox['type']) && in_array($outbox['type'], $types)) {
if (isset($outbox['type']) && in_array($outbox['type'], $types)) {
Log::info('handle ordered collection');
$this->handleOrderedCollection();
}
@ -89,19 +92,20 @@ class RemoteFollowImportRecent implements ShouldQueue
{
$outbox = $this->outbox;
if(!isset($outbox['next']) && !isset($outbox['first']['next']) && $this->cursor !== 1) {
if (!isset($outbox['next']) && !isset($outbox['first']['next']) && $this->cursor !== 1) {
$this->cursor = 40;
$outbox['next'] = false;
}
if($outbox['type'] == 'OrderedCollectionPage') {
if ($outbox['type'] == 'OrderedCollectionPage') {
$this->nextUrl = $outbox['next'];
}
if(isset($outbox['first']) && !is_array($outbox['first'])) {
if (isset($outbox['first']) && !is_array($outbox['first'])) {
// Mastodon detected
Log::info('Mastodon detected...');
$this->nextUrl = $outbox['first'];
return $this->fetchOutbox($this->nextUrl);
} else {
// Pleroma detected.
@ -110,33 +114,31 @@ class RemoteFollowImportRecent implements ShouldQueue
$orderedItems = isset($outbox['orderedItems']) ? $outbox['orderedItems'] : $outbox['first']['orderedItems'];
}
foreach($orderedItems as $item) {
foreach ($orderedItems as $item) {
Log::info('Parsing items...');
$parsed = $this->parseObject($item);
if($parsed !== 0) {
if ($parsed !== 0) {
Log::info('Found media!');
$this->importActivity($item);
}
}
if($this->cursor < 40 && $this->mediaCount < 9) {
if ($this->cursor < 40 && $this->mediaCount < 9) {
$this->cursor++;
$this->mediaCount++;
$this->fetchOutbox($this->nextUrl);
}
}
public function parseObject($parsed)
{
if($parsed['type'] !== 'Create') {
if ($parsed['type'] !== 'Create') {
return 0;
}
$activity = $parsed['object'];
if(isset($activity['attachment']) && !empty($activity['attachment'])) {
if (isset($activity['attachment']) && !empty($activity['attachment'])) {
return $this->detectSupportedMedia($activity['attachment']);
}
}
@ -146,7 +148,7 @@ class RemoteFollowImportRecent implements ShouldQueue
$supported = $this->supported;
$count = 0;
foreach($attachments as $media) {
foreach ($attachments as $media) {
$mime = $media['mediaType'];
$count = in_array($mime, $supported) ? ($count + 1) : $count;
}
@ -161,11 +163,11 @@ class RemoteFollowImportRecent implements ShouldQueue
$attachments = $activity['object']['attachment'];
$caption = str_limit($activity['object']['content'], 125);
if(Status::whereUrl($activity['id'])->count() !== 0) {
if (Status::whereUrl($activity['id'])->count() !== 0) {
return true;
}
$status = new Status;
$status = new Status();
$status->profile_id = $profile->id;
$status->url = $activity['id'];
$status->local = false;
@ -174,24 +176,24 @@ class RemoteFollowImportRecent implements ShouldQueue
$count = 0;
foreach($attachments as $media) {
Log::info($media['mediaType'] . ' - ' . $media['url']);
foreach ($attachments as $media) {
Log::info($media['mediaType'].' - '.$media['url']);
$url = $media['url'];
$mime = $media['mediaType'];
if(!in_array($mime, $supported)) {
Log::info('Invalid media, skipping. ' . $mime);
if (!in_array($mime, $supported)) {
Log::info('Invalid media, skipping. '.$mime);
continue;
}
$count++;
if($count === 1) {
if ($count === 1) {
$status->save();
}
$this->importMedia($url, $mime, $status);
}
Log::info(count($attachments) . ' media found...');
Log::info(count($attachments).' media found...');
if($count !== 0) {
if ($count !== 0) {
NewStatusPipeline::dispatch($status, $status->media->first());
}
}
@ -199,17 +201,18 @@ class RemoteFollowImportRecent implements ShouldQueue
public function importMedia($url, $mime, $status)
{
$user = $this->profile;
$monthHash = hash('sha1', date('Y') . date('m'));
$userHash = hash('sha1', $user->id . (string) $user->created_at);
$monthHash = hash('sha1', date('Y').date('m'));
$userHash = hash('sha1', $user->id.(string) $user->created_at);
$storagePath = "public/m/{$monthHash}/{$userHash}";
try {
$info = pathinfo($url);
$img = file_get_contents($url);
$file = '/tmp/' . str_random(12) . $info['basename'];
$file = '/tmp/'.str_random(12).$info['basename'];
file_put_contents($file, $img);
$path = Storage::putFile($storagePath, new File($file), 'public');
$media = new Media;
$media = new Media();
$media->status_id = $status->id;
$media->profile_id = $status->profile_id;
$media->user_id = null;
@ -225,5 +228,4 @@ class RemoteFollowImportRecent implements ShouldQueue
return false;
}
}
}

View file

@ -2,18 +2,17 @@
namespace App\Jobs\RemoteFollowPipeline;
use Zttp\Zttp;
use App\Jobs\AvatarPipeline\CreateAvatar;
use App\{Profile};
use GuzzleHttp\Client;
use HttpSignatures\Context;
use HttpSignatures\GuzzleHttpSignatures;
use App\Jobs\RemoteFollowPipeline\RemoteFollowImportRecent;
use App\Jobs\AvatarPipeline\CreateAvatar;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Zttp\Zttp;
class RemoteFollowPipeline implements ShouldQueue
{
@ -44,11 +43,12 @@ class RemoteFollowPipeline implements ShouldQueue
$follower = $this->follower;
$url = $this->url;
if(Profile::whereRemoteUrl($url)->count() !== 0) {
if (Profile::whereRemoteUrl($url)->count() !== 0) {
return true;
}
$this->discover($url);
return true;
}
@ -64,7 +64,7 @@ class RemoteFollowPipeline implements ShouldQueue
$client = new Client(['handler' => $handlerStack]);
$response = Zttp::withHeaders([
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'User-Agent' => 'PixelFedBot v0.1 - https://pixelfed.org'
'User-Agent' => 'PixelFedBot v0.1 - https://pixelfed.org',
])->get($url);
$this->response = $response->json();
@ -78,7 +78,7 @@ class RemoteFollowPipeline implements ShouldQueue
$username = $res['preferredUsername'];
$remoteUsername = "@{$username}@{$domain}";
$profile = new Profile;
$profile = new Profile();
$profile->user_id = null;
$profile->domain = $domain;
$profile->username = $remoteUsername;
@ -99,7 +99,7 @@ class RemoteFollowPipeline implements ShouldQueue
$activity = Zttp::withHeaders(['Content-Type' => 'application/activity+json'])->post($url, [
'type' => 'Follow',
'object' => $this->follower->url()
'object' => $this->follower->url(),
]);
}
}

View file

@ -2,14 +2,14 @@
namespace App\Jobs\StatusPipeline;
use Cache, Redis;
use App\{Media, Status};
use App\Jobs\ImageOptimizePipeline\ImageOptimize;
use App\Status;
use Cache;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Redis;
class NewStatusPipeline implements ShouldQueue
{
@ -39,9 +39,9 @@ class NewStatusPipeline implements ShouldQueue
StatusEntityLexer::dispatch($status);
//StatusActivityPubDeliver::dispatch($status);
Cache::forever('post.' . $status->id, $status);
Cache::forever('post.'.$status->id, $status);
$redis = Redis::connection();
$redis->lpush(config('cache.prefix').':user.' . $status->profile_id . '.posts', $status->id);
$redis->lpush(config('cache.prefix').':user.'.$status->profile_id.'.posts', $status->id);
}
}

View file

@ -2,18 +2,19 @@
namespace App\Jobs\StatusPipeline;
use App\{Media, Status};
use App\Status;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class StatusActivityPubDeliver implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $status;
/**
* Create a new job instance.
*

View file

@ -2,12 +2,14 @@
namespace App\Jobs\StatusPipeline;
use App\{Media, Notification, StatusHashtag, Status};
use App\Notification;
use App\Status;
use App\StatusHashtag;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class StatusDelete implements ShouldQueue
{
@ -38,28 +40,27 @@ class StatusDelete implements ShouldQueue
public function unlinkRemoveMedia($status)
{
if($status->media()->count() == 0) {
if ($status->media()->count() == 0) {
return;
}
foreach($status->media as $media) {
foreach ($status->media as $media) {
$thumbnail = storage_path("app/{$media->thumbnail_path}");
$photo = storage_path("app/{$media->media_path}");
try {
if(is_file($thumbnail)) {
if (is_file($thumbnail)) {
unlink($thumbnail);
}
if(is_file($photo)) {
if (is_file($photo)) {
unlink($photo);
}
$media->delete();
} catch (Exception $e) {
}
}
$comments = Status::where('in_reply_to_id', $status->id)->get();
foreach($comments as $comment) {
foreach ($comments as $comment) {
$comment->in_reply_to_id = null;
$comment->save();
Notification::whereItemType('App\Status')

View file

@ -2,23 +2,20 @@
namespace App\Jobs\StatusPipeline;
use DB, Cache;
use App\{
Hashtag,
Media,
Mention,
Profile,
Status,
StatusHashtag
};
use App\Util\Lexer\Hashtag as HashtagLexer;
use App\Util\Lexer\{Autolink, Extractor};
use App\Hashtag;
use App\Jobs\MentionPipeline\MentionPipeline;
use App\Mention;
use App\Profile;
use App\Status;
use App\StatusHashtag;
use App\Util\Lexer\Autolink;
use App\Util\Lexer\Extractor;
use DB;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Jobs\MentionPipeline\MentionPipeline;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class StatusEntityLexer implements ShouldQueue
{
@ -83,7 +80,7 @@ class StatusEntityLexer implements ShouldQueue
$tags = array_unique($this->entities['hashtags']);
$status = $this->status;
foreach($tags as $tag) {
foreach ($tags as $tag) {
DB::transaction(function () use ($status, $tag) {
$slug = str_slug($tag);
$hashtag = Hashtag::firstOrCreate(
@ -101,15 +98,15 @@ class StatusEntityLexer implements ShouldQueue
$mentions = array_unique($this->entities['mentions']);
$status = $this->status;
foreach($mentions as $mention) {
foreach ($mentions as $mention) {
$mentioned = Profile::whereUsername($mention)->firstOrFail();
if(empty($mentioned) || !isset($mentioned->id)) {
if (empty($mentioned) || !isset($mentioned->id)) {
continue;
}
DB::transaction(function () use ($status, $mentioned) {
$m = new Mention;
$m = new Mention();
$m->status_id = $status->id;
$m->profile_id = $mentioned->id;
$m->save();
@ -118,5 +115,4 @@ class StatusEntityLexer implements ShouldQueue
});
}
}
}

View file

@ -29,14 +29,16 @@ class Like extends Model
public function toText()
{
$actorName = $this->actor->username;
return "{$actorName} " . __('notification.likedPhoto');
return "{$actorName} ".__('notification.likedPhoto');
}
public function toHtml()
{
$actorName = $this->actor->username;
$actorUrl = $this->actor->url();
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> " .
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> ".
__('notification.likedPhoto');
}
}

View file

@ -6,7 +6,6 @@ use App\EmailVerification;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class ConfirmEmail extends Mailable
{

View file

@ -2,9 +2,9 @@
namespace App;
use Storage;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Storage;
class Media extends Model
{
@ -21,6 +21,7 @@ class Media extends Model
{
$path = $this->media_path;
$url = Storage::url($path);
return url($url);
}
@ -28,6 +29,7 @@ class Media extends Model
{
$path = $this->thumbnail_path;
$url = Storage::url($path);
return url($url);
}
}

View file

@ -29,14 +29,16 @@ class Mention extends Model
public function toText()
{
$actorName = $this->status->profile->username;
return "{$actorName} " . __('notification.mentionedYou');
return "{$actorName} ".__('notification.mentionedYou');
}
public function toHtml()
{
$actorName = $this->status->profile->username;
$actorUrl = $this->status->profile->url();
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> " .
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> ".
__('notification.mentionedYou');
}
}

View file

@ -35,5 +35,4 @@ class Notification extends Model
{
return $this->belongsTo(Status::class, 'item_id', 'id');
}
}

View file

@ -2,8 +2,10 @@
namespace App\Observers;
use App\{Profile, User, UserSetting};
use App\Jobs\AvatarPipeline\CreateAvatar;
use App\Profile;
use App\User;
use App\UserSetting;
class UserObserver
{
@ -11,19 +13,20 @@ class UserObserver
* Listen to the User created event.
*
* @param \App\User $user
*
* @return void
*/
public function saved(User $user)
{
if(empty($user->profile)) {
$profile = new Profile;
if (empty($user->profile)) {
$profile = new Profile();
$profile->user_id = $user->id;
$profile->username = $user->username;
$profile->name = $user->name;
$pkiConfig = [
"digest_alg" => "sha512",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$pki = openssl_pkey_new($pkiConfig);
openssl_pkey_export($pki, $pki_private);
@ -37,11 +40,10 @@ class UserObserver
CreateAvatar::dispatch($profile);
}
if(empty($user->settings)) {
$settings = new UserSetting;
if (empty($user->settings)) {
$settings = new UserSetting();
$settings->user_id = $user->id;
$settings->save();
}
}
}

View file

@ -2,10 +2,12 @@
namespace App;
use Auth, Cache, Storage;
use App\Util\Lexer\PrettyNumber;
use Auth;
use Cache;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Storage;
class Profile extends Model
{
@ -30,27 +32,28 @@ class Profile extends Model
public function url($suffix = '')
{
if($this->remote_url) {
if ($this->remote_url) {
return $this->remote_url;
} else {
return url($this->username . $suffix);
return url($this->username.$suffix);
}
}
public function localUrl($suffix = '')
{
return url($this->username . $suffix);
return url($this->username.$suffix);
}
public function permalink($suffix = '')
{
return url('users/' . $this->username . $suffix);
return url('users/'.$this->username.$suffix);
}
public function emailUrl()
{
$domain = parse_url(config('app.url'), PHP_URL_HOST);
return $this->username . '@' . $domain;
return $this->username.'@'.$domain;
}
public function statuses()
@ -61,7 +64,7 @@ class Profile extends Model
public function followingCount($short = false)
{
$count = $this->following()->count();
if($short) {
if ($short) {
return PrettyNumber::convert($count);
} else {
return $count;
@ -71,7 +74,7 @@ class Profile extends Model
public function followerCount($short = false)
{
$count = $this->followers()->count();
if($short) {
if ($short) {
return PrettyNumber::convert($count);
} else {
return $count;
@ -81,7 +84,7 @@ class Profile extends Model
public function following()
{
return $this->belongsToMany(
Profile::class,
self::class,
'followers',
'profile_id',
'following_id'
@ -91,7 +94,7 @@ class Profile extends Model
public function followers()
{
return $this->belongsToMany(
Profile::class,
self::class,
'followers',
'following_id',
'profile_id'
@ -126,18 +129,20 @@ class Profile extends Model
public function avatar()
{
return $this->hasOne(Avatar::class)->withDefault([
'media_path' => 'public/avatars/default.png'
'media_path' => 'public/avatars/default.png',
]);
}
public function avatarUrl()
{
$url = Cache::remember("avatar:{$this->id}", 1440, function() {
$url = Cache::remember("avatar:{$this->id}", 1440, function () {
$path = optional($this->avatar)->media_path;
$version = hash('sha1', $this->avatar->created_at);
$path = "{$path}?v={$version}";
return url(Storage::url($path));
});
return $url;
}
@ -167,8 +172,8 @@ class Profile extends Model
->limit(3)
->pluck('following_id');
$recommended = [];
foreach($following as $follow) {
$recommended[] = Profile::findOrFail($follow);
foreach ($following as $follow) {
$recommended[] = self::findOrFail($follow);
}
return $recommended;
@ -176,9 +181,10 @@ class Profile extends Model
public function keyId()
{
if($this->remote_url) {
if ($this->remote_url) {
return;
}
return $this->permalink('#main-key');
}
}

View file

@ -2,9 +2,10 @@
namespace App\Providers;
use App\User;
use Auth, Horizon;
use App\Observers\UserObserver;
use App\User;
use Auth;
use Horizon;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
@ -26,33 +27,38 @@ class AppServiceProvider extends ServiceProvider
return Auth::check() && $request->user()->is_admin;
});
Blade::directive('prettyNumber', function($expression) {
Blade::directive('prettyNumber', function ($expression) {
$num = $expression;
$abbrevs = array(12 => "T", 9 => "B", 6 => "M", 3 => "K", 0 => "");
foreach($abbrevs as $exponent => $abbrev) {
if($expression >= pow(10, $exponent)) {
$abbrevs = [12 => 'T', 9 => 'B', 6 => 'M', 3 => 'K', 0 => ''];
foreach ($abbrevs as $exponent => $abbrev) {
if ($expression >= pow(10, $exponent)) {
$display_num = $expression / pow(10, $exponent);
$num = number_format($display_num,0) . $abbrev;
$num = number_format($display_num, 0).$abbrev;
return "<?php echo '$num'; ?>";
}
}
return "<?php echo $num; ?>";
});
Blade::directive('prettySize', function($expression) {
Blade::directive('prettySize', function ($expression) {
$size = intval($expression);
$precision = 0;
$short = true;
$units = $short ?
['B','k','M','G','T','P','E','Z','Y'] :
['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
for($i = 0; ($size / 1024) > 0.9; $i++, $size /= 1024) {}
['B', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] :
['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
for ($i = 0; ($size / 1024) > 0.9; $i++, $size /= 1024) {
}
$res = round($size, $precision).$units[$i];
return "<?php echo '$res'; ?>";
});
Blade::directive('maxFileSize', function() {
Blade::directive('maxFileSize', function () {
$value = config('pixelfed.max_photo_size');
return \App\Util\Lexer\PrettyNumber::size($value, true);
});
}

View file

@ -2,7 +2,6 @@
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider

View file

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{

View file

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{

View file

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{

View file

@ -10,7 +10,7 @@ class Report extends Model
public function url()
{
return url('/i/admin/reports/show/' . $this->id);
return url('/i/admin/reports/show/'.$this->id);
}
public function reporter()
@ -30,6 +30,7 @@ class Report extends Model
$column = 'id';
break;
}
return (new $class())->where($column, $this->object_id)->firstOrFail();
}

View file

@ -2,9 +2,10 @@
namespace App;
use Auth, Storage;
use Auth;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Storage;
class Status extends Model
{
@ -36,6 +37,7 @@ class Status extends Model
{
$media = $this->firstMedia();
$type = explode('/', $media->mime);
return $type[0];
}
@ -43,9 +45,10 @@ class Status extends Model
{
$type = $this->viewType();
$is_nsfw = !$showNsfw ? $this->is_nsfw : false;
if($this->media->count() == 0 || $is_nsfw || $type != 'image') {
return "data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
if ($this->media->count() == 0 || $is_nsfw || $type != 'image') {
return 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==';
}
return url(Storage::url($this->firstMedia()->thumbnail_path));
}
@ -53,11 +56,12 @@ class Status extends Model
{
$id = $this->id;
$username = $this->profile->username;
$path = config('app.url') . "/p/{$username}/{$id}";
if(!is_null($this->in_reply_to_id)) {
$path = config('app.url')."/p/{$username}/{$id}";
if (!is_null($this->in_reply_to_id)) {
$pid = $this->in_reply_to_id;
$path = config('app.url') . "/p/{$username}/{$pid}/c/{$id}";
$path = config('app.url')."/p/{$username}/{$pid}/c/{$id}";
}
return url($path);
}
@ -65,13 +69,14 @@ class Status extends Model
{
$id = $this->id;
$username = $this->profile->username;
$path = config('app.url') . "/p/{$username}/{$id}{$suffix}";
$path = config('app.url')."/p/{$username}/{$id}{$suffix}";
return url($path);
}
public function editUrl()
{
return $this->url() . '/edit';
return $this->url().'/edit';
}
public function mediaUrl()
@ -79,7 +84,8 @@ class Status extends Model
$media = $this->firstMedia();
$path = $media->media_path;
$hash = is_null($media->processed_at) ? md5('unprocessed') : md5($media->created_at);
$url = Storage::url($path) . "?v={$hash}";
$url = Storage::url($path)."?v={$hash}";
return url($url);
}
@ -91,39 +97,42 @@ class Status extends Model
public function liked() : bool
{
$profile = Auth::user()->profile;
return Like::whereProfileId($profile->id)->whereStatusId($this->id)->count();
}
public function comments()
{
return $this->hasMany(Status::class, 'in_reply_to_id');
return $this->hasMany(self::class, 'in_reply_to_id');
}
public function bookmarked()
{
if(!Auth::check()) {
if (!Auth::check()) {
return 0;
}
$profile = Auth::user()->profile;
return Bookmark::whereProfileId($profile->id)->whereStatusId($this->id)->count();
}
public function shares()
{
return $this->hasMany(Status::class, 'reblog_of_id');
return $this->hasMany(self::class, 'reblog_of_id');
}
public function shared() : bool
{
$profile = Auth::user()->profile;
return Status::whereProfileId($profile->id)->whereReblogOfId($this->id)->count();
return self::whereProfileId($profile->id)->whereReblogOfId($this->id)->count();
}
public function parent()
{
$parent = $this->in_reply_to_id ?? $this->reblog_of_id;
if(!empty($parent)) {
return Status::findOrFail($parent);
if (!empty($parent)) {
return self::findOrFail($parent);
}
}
@ -158,45 +167,48 @@ class Status extends Model
public function reportUrl()
{
return route('report.form') . "?type=post&id={$this->id}";
return route('report.form')."?type=post&id={$this->id}";
}
public function toActivityStream()
{
$media = $this->media;
$mediaCollection = [];
foreach($media as $image) {
foreach ($media as $image) {
$mediaCollection[] = [
"type" => "Link",
"href" => $image->url(),
"mediaType" => $image->mime
'type' => 'Link',
'href' => $image->url(),
'mediaType' => $image->mime,
];
}
$obj = [
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Image",
"name" => null,
"url" => $mediaCollection
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Image',
'name' => null,
'url' => $mediaCollection,
];
return $obj;
}
public function replyToText()
{
$actorName = $this->profile->username;
return "{$actorName} " . __('notification.commented');
return "{$actorName} ".__('notification.commented');
}
public function replyToHtml()
{
$actorName = $this->profile->username;
$actorUrl = $this->profile->url();
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> " .
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> ".
__('notification.commented');
}
public function recentComments()
{
return $this->comments()->orderBy('created_at','desc')->take(3);
return $this->comments()->orderBy('created_at', 'desc')->take(3);
}
}

View file

@ -7,11 +7,10 @@ use League\Fractal;
class ProfileOutbox extends Fractal\TransformerAbstract
{
public function transform(Profile $profile)
{
$count = $profile->statuses()->count();
$statuses = $profile->statuses()->has('media')->orderBy('id','desc')->take(20)->get()->map(function($i, $k) {
$statuses = $profile->statuses()->has('media')->orderBy('id', 'desc')->take(20)->get()->map(function ($i, $k) {
$item = [
'id' => $i->permalink(),
// TODO: handle other types
@ -19,7 +18,7 @@ class ProfileOutbox extends Fractal\TransformerAbstract
'actor' => $i->profile->url(),
'published' => $i->created_at->toISO8601String(),
'to' => [
'https://www.w3.org/ns/activitystreams#Public'
'https://www.w3.org/ns/activitystreams#Public',
],
'cc' => [
$i->profile->permalink('/followers'),
@ -41,7 +40,7 @@ class ProfileOutbox extends Fractal\TransformerAbstract
'attributedTo' => $i->profile->permalink(),
'to' => [
// TODO: handle proper scope
'https://www.w3.org/ns/activitystreams#Public'
'https://www.w3.org/ns/activitystreams#Public',
],
'cc' => [
// TODO: add cc's
@ -57,12 +56,13 @@ class ProfileOutbox extends Fractal\TransformerAbstract
'type' => 'Document',
'mediaType' => $i->firstMedia()->mime,
'url' => $i->firstMedia()->url(),
'name' => null
]
'name' => null,
],
],
'tag' => [],
],
'tag' => []
]
];
return $item;
});
@ -71,8 +71,7 @@ class ProfileOutbox extends Fractal\TransformerAbstract
'id' => $profile->permalink('/outbox'),
'type' => 'OrderedCollection',
'totalItems' => $count,
'orderedItems' => $statuses
'orderedItems' => $statuses,
];
}
}

View file

@ -7,7 +7,6 @@ use League\Fractal;
class ProfileTransformer extends Fractal\TransformerAbstract
{
public function transform(Profile $profile)
{
return [
@ -15,11 +14,11 @@ class ProfileTransformer extends Fractal\TransformerAbstract
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
[
"manuallyApprovesFollowers" => "as:manuallyApprovesFollowers",
"featured" => [
"https://pixelfed.org/ns#featured" => ["@type" => "@id"],
]
]
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'featured' => [
'https://pixelfed.org/ns#featured' => ['@type' => '@id'],
],
],
],
'id' => $profile->permalink(),
'type' => 'Person',
@ -36,19 +35,18 @@ class ProfileTransformer extends Fractal\TransformerAbstract
// 'follower_count' => $profile->followers()->count(),
// 'following_count' => $profile->following()->count(),
'publicKey' => [
'id' => $profile->permalink() . '#main-key',
'id' => $profile->permalink().'#main-key',
'owner' => $profile->permalink(),
'publicKeyPem' => $profile->public_key
'publicKeyPem' => $profile->public_key,
],
'endpoints' => [
'sharedInbox' => config('routes.api.sharedInbox')
'sharedInbox' => config('routes.api.sharedInbox'),
],
'icon' => [
'type' => 'Image',
'mediaType' => 'image/jpeg',
'url' => $profile->avatarUrl()
]
'url' => $profile->avatarUrl(),
],
];
}
}

View file

@ -2,12 +2,11 @@
namespace App\Transformer\ActivityPub;
use App\{Profile, Status};
use App\Status;
use League\Fractal;
class StatusTransformer extends Fractal\TransformerAbstract
{
public function transform(Status $status)
{
return [
@ -15,11 +14,11 @@ class StatusTransformer extends Fractal\TransformerAbstract
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
[
"manuallyApprovesFollowers" => "as:manuallyApprovesFollowers",
"featured" => [
"https://pixelfed.org/ns#featured" => ["@type" => "@id"],
]
]
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'featured' => [
'https://pixelfed.org/ns#featured' => ['@type' => '@id'],
],
],
],
'id' => $status->url(),
@ -37,7 +36,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
'attributedTo' => $status->profile->permalink(),
'to' => [
// TODO: handle proper scope
'https://www.w3.org/ns/activitystreams#Public'
'https://www.w3.org/ns/activitystreams#Public',
],
'cc' => [
// TODO: add cc's
@ -46,16 +45,15 @@ class StatusTransformer extends Fractal\TransformerAbstract
'sensitive' => (bool) $status->is_nsfw,
'atomUri' => $status->url(),
'inReplyToAtomUri' => null,
'attachment' => $status->media->map(function($media) {
'attachment' => $status->media->map(function ($media) {
return [
'type' => 'Document',
'mediaType' => $media->mime,
'url' => $media->url(),
'name' => null
'name' => null,
];
}),
'tag' => []
'tag' => [],
];
}
}

View file

@ -27,7 +27,7 @@ class AccountTransformer extends Fractal\TransformerAbstract
'header_static' => '',
'moved' => null,
'fields' => null,
'bot' => null
'bot' => null,
];
}
}

View file

@ -10,7 +10,7 @@ class ApplicationTransformer extends Fractal\TransformerAbstract
{
return [
'name' => '',
'website' => null
'website' => null,
];
}
}

View file

@ -4,7 +4,6 @@ namespace App\Transformer\Api;
use App\Hashtag;
use League\Fractal;
use League\Fractal\Serializer\ArraySerializer;
class HashtagTransformer extends Fractal\TransformerAbstract
{

View file

@ -4,7 +4,6 @@ namespace App\Transformer\Api;
use App\Media;
use League\Fractal;
use League\Fractal\Serializer\ArraySerializer;
class MediaTransformer extends Fractal\TransformerAbstract
{
@ -18,7 +17,7 @@ class MediaTransformer extends Fractal\TransformerAbstract
'preview_url' => $media->thumbnailUrl(),
'text_url' => null,
'meta' => null,
'description' => null
'description' => null,
];
}
}

View file

@ -11,7 +11,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
'account',
'mentions',
'media_attachments',
'tags'
'tags',
];
public function transform(Status $status)
@ -39,31 +39,35 @@ class StatusTransformer extends Fractal\TransformerAbstract
'visibility' => $status->visibility,
'application' => null,
'language' => null,
'pinned' => null
'pinned' => null,
];
}
public function includeAccount(Status $status)
{
$account = $status->profile;
return $this->item($account, new AccountTransformer);
return $this->item($account, new AccountTransformer());
}
public function includeMentions(Status $status)
{
$mentions = $status->mentions;
return $this->collection($mentions, new MentionTransformer);
return $this->collection($mentions, new MentionTransformer());
}
public function includeMediaAttachments(Status $status)
{
$media = $status->media;
return $this->collection($media, new MediaTransformer);
return $this->collection($media, new MediaTransformer());
}
public function includeTags(Status $status)
{
$tags = $status->hashtags;
return $this->collection($tags, new HashtagTransformer);
return $this->collection($tags, new HashtagTransformer());
}
}

View file

@ -2,9 +2,9 @@
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
@ -42,7 +42,7 @@ class User extends Authenticatable
public function url()
{
return url(config('app.url') . '/' . $this->username);
return url(config('app.url').'/'.$this->username);
}
public function settings()

View file

@ -10,6 +10,6 @@ class UserFilter extends Model
'user_id',
'filterable_id',
'filterable_type',
'filter_type'
'filter_type',
];
}

View file

@ -4,10 +4,10 @@ namespace App\Util\ActivityPub\Concern;
use Zttp\Zttp;
class HTTPSignature {
class HTTPSignature
{
protected $localhosts = [
'127.0.0.1', 'localhost', '::1'
'127.0.0.1', 'localhost', '::1',
];
public $profile;
public $is_url;
@ -15,20 +15,22 @@ class HTTPSignature {
public function validateUrl()
{
// If the profile exists, assume its valid
if($this->is_url === false) {
if ($this->is_url === false) {
return true;
}
$url = $this->profile;
try {
$url = filter_var($url, FILTER_VALIDATE_URL);
$parsed = parse_url($url, PHP_URL_HOST);
if(!$parsed || in_array($parsed, $this->localhosts)) {
if (!$parsed || in_array($parsed, $this->localhosts)) {
return false;
}
} catch (Exception $e) {
return false;
}
return true;
}
@ -37,10 +39,10 @@ class HTTPSignature {
$this->profile = $profile;
$this->is_url = $is_url;
$valid = $this->validateUrl();
if(!$valid) {
if (!$valid) {
throw new \Exception('Invalid URL provided');
}
if($is_url && isset($profile->public_key) && $profile->public_key) {
if ($is_url && isset($profile->public_key) && $profile->public_key) {
return $profile->public_key;
}
@ -48,7 +50,7 @@ class HTTPSignature {
$url = $this->profile;
$res = Zttp::timeout(30)->withHeaders([
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'User-Agent' => 'PixelFedBot v0.1 - https://pixelfed.org'
'User-Agent' => 'PixelFedBot v0.1 - https://pixelfed.org',
])->get($url);
$actor = json_decode($res->getBody(), true);
} catch (Exception $e) {
@ -72,23 +74,21 @@ class HTTPSignature {
$headers = [
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Date' => date('D, d M Y h:i:s') . ' GMT',
'Date' => date('D, d M Y h:i:s').' GMT',
'Content-Type' => 'application/activity+json',
'User-Agent' => 'PixelFedBot - https://pixelfed.org'
'User-Agent' => 'PixelFedBot - https://pixelfed.org',
];
$response = $client->post($url, [
'options' => [
'allow_redirects' => false,
'verify' => true,
'timeout' => 30
'timeout' => 30,
],
'headers' => $headers,
'body' => $body
'body' => $body,
]);
return $response->getBody();
}
}

View file

@ -2,10 +2,10 @@
namespace App\Util\ActivityPub;
use \Zttp\Zttp;
class DiscoverActor {
use Zttp\Zttp;
class DiscoverActor
{
protected $url;
protected $response;
@ -18,9 +18,10 @@ class DiscoverActor {
{
$res = Zttp::withHeaders([
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'User-Agent' => 'PixelFedBot - https://pixelfed.org'
'User-Agent' => 'PixelFedBot - https://pixelfed.org',
])->get($this->url);
$this->response = $res->body();
return $this;
}
@ -39,11 +40,10 @@ class DiscoverActor {
$this->fetch();
$res = $this->getResponse();
if(empty($res) || !in_array('type', $res) || $res['type'] !== 'Person') {
if (empty($res) || !in_array('type', $res) || $res['type'] !== 'Person') {
throw new \Exception('Invalid Actor Object');
}
return $res;
}
}

View file

@ -2,11 +2,11 @@
namespace App\Util\ActivityPub;
use App\Jobs\AvatarPipeline\CreateAvatar;
use App\{Follower, Like, Profile, Like, Status, User};
class Inbox {
use App\Like;
use App\Profile;
class Inbox
{
protected $request;
protected $profile;
protected $payload;
@ -58,12 +58,11 @@ class Inbox {
{
$actor = $this->payload['object'];
$target = $this->profile;
}
public function actorFirstOrCreate($actorUrl)
{
if(Profile::whereRemoteUrl($actorUrl)->count() !== 0) {
if (Profile::whereRemoteUrl($actorUrl)->count() !== 0) {
return Profile::whereRemoteUrl($actorUrl)->firstOrFail();
}
@ -73,7 +72,7 @@ class Inbox {
$username = $res['preferredUsername'];
$remoteUsername = "@{$username}@{$domain}";
$profile = new Profile;
$profile = new Profile();
$profile->user_id = null;
$profile->domain = $domain;
$profile->username = $remoteUsername;
@ -82,7 +81,5 @@ class Inbox {
$profile->sharedInbox = $res['endpoints']['sharedInbox'];
$profile->remote_url = $res['url'];
$profile->save();
}
}

View file

@ -12,7 +12,7 @@ class HashPreprocessor implements \Bitverse\Identicon\Preprocessor\PreprocessorI
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function process($string)
{

View file

@ -5,17 +5,12 @@
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Mike Cochrane, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
namespace App\Util\Lexer;
use App\Util\Lexer\Regex;
use App\Util\Lexer\Extractor;
use App\Util\Lexer\StringUtils;
/**
* Twitter Autolink Class
* Twitter Autolink Class.
*
* Parses tweets and generates HTML anchor tags around URLs, usernames,
* username/list pairs and hashtags.
@ -28,11 +23,9 @@ use App\Util\Lexer\StringUtils;
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Mike Cochrane, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
class Autolink extends Regex
{
/**
* CSS class for auto-linked URLs.
*
@ -134,14 +127,13 @@ class Autolink extends Regex
protected $target = '_blank';
/**
* attribute for invisible span tag
* attribute for invisible span tag.
*
* @var string
*/
protected $invisibleTagAttrs = "style='position:absolute;left:-9999px;'";
/**
*
* @var Extractor
*/
protected $extractor = null;
@ -185,10 +177,10 @@ class Autolink extends Regex
parent::__construct($tweet);
}
$this->extractor = Extractor::create();
$this->url_base_user = config('app.url') . '/';
$this->url_base_list = config('app.url') . '/';
$this->url_base_hash = config('app.url') . "/discover/tags/";
$this->url_base_cash = config('app.url') . '/search?q=%24';
$this->url_base_user = config('app.url').'/';
$this->url_base_list = config('app.url').'/';
$this->url_base_hash = config('app.url').'/discover/tags/';
$this->url_base_cash = config('app.url').'/search?q=%24';
}
/**
@ -211,6 +203,7 @@ class Autolink extends Regex
public function setURLClass($v)
{
$this->class_url = trim($v);
return $this;
}
@ -234,6 +227,7 @@ class Autolink extends Regex
public function setUsernameClass($v)
{
$this->class_user = trim($v);
return $this;
}
@ -257,6 +251,7 @@ class Autolink extends Regex
public function setListClass($v)
{
$this->class_list = trim($v);
return $this;
}
@ -280,6 +275,7 @@ class Autolink extends Regex
public function setHashtagClass($v)
{
$this->class_hash = trim($v);
return $this;
}
@ -303,6 +299,7 @@ class Autolink extends Regex
public function setCashtagClass($v)
{
$this->class_cash = trim($v);
return $this;
}
@ -326,6 +323,7 @@ class Autolink extends Regex
public function setNoFollow($v)
{
$this->nofollow = $v;
return $this;
}
@ -359,6 +357,7 @@ class Autolink extends Regex
public function setExternal($v)
{
$this->external = $v;
return $this;
}
@ -390,15 +389,18 @@ class Autolink extends Regex
public function setTarget($v)
{
$this->target = trim($v);
return $this;
}
/**
* Autolink with entities
* Autolink with entities.
*
* @param string $tweet
* @param array $entities
*
* @return string
*
* @since 1.1.0
*/
public function autoLinkEntities($tweet = null, $entities = null)
@ -428,6 +430,7 @@ class Autolink extends Regex
$beginIndex = $entity['indices'][1];
}
$text .= StringUtils::substr($tweet, $beginIndex, StringUtils::strlen($tweet));
return $text;
}
@ -436,13 +439,15 @@ class Autolink extends Regex
*
* @param string The tweet to be converted
* @param mixed The entities info
*
* @return string that auto-link HTML added
*
* @since 1.1.0
*/
public function autoLinkWithJson($tweet = null, $json = null)
{
// concatenate entities
$entities = array();
$entities = [];
if (is_object($json)) {
$json = $this->object2array($json);
}
@ -460,13 +465,15 @@ class Autolink extends Regex
}
$entities = $this->extractor->removeOverlappingEntities($entities);
return $this->autoLinkEntities($tweet, $entities);
}
/**
* convert Object to Array
* convert Object to Array.
*
* @param mixed $obj
*
* @return array
*/
protected function object2array($obj)
@ -477,6 +484,7 @@ class Autolink extends Regex
$array[$key] = $this->object2array($var);
}
}
return $array;
}
@ -484,7 +492,9 @@ class Autolink extends Regex
* Auto-link hashtags, URLs, usernames and lists.
*
* @param string The tweet to be converted
*
* @return string that auto-link HTML added
*
* @since 1.1.0
*/
public function autoLink($tweet = null)
@ -493,6 +503,7 @@ class Autolink extends Regex
$tweet = $this->tweet;
}
$entities = $this->extractor->extractURLWithoutProtocol(false)->extractEntitiesWithIndices($tweet);
return $this->autoLinkEntities($tweet, $entities);
}
@ -502,6 +513,7 @@ class Autolink extends Regex
* added.
*
* @return string that auto-link HTML added
*
* @since 1.1.0
*/
public function autoLinkUsernamesAndLists($tweet = null)
@ -510,6 +522,7 @@ class Autolink extends Regex
$tweet = $this->tweet;
}
$entities = $this->extractor->extractMentionsOrListsWithIndices($tweet);
return $this->autoLinkEntities($tweet, $entities);
}
@ -518,6 +531,7 @@ class Autolink extends Regex
* added.
*
* @return string that auto-link HTML added
*
* @since 1.1.0
*/
public function autoLinkHashtags($tweet = null)
@ -526,6 +540,7 @@ class Autolink extends Regex
$tweet = $this->tweet;
}
$entities = $this->extractor->extractHashtagsWithIndices($tweet);
return $this->autoLinkEntities($tweet, $entities);
}
@ -535,6 +550,7 @@ class Autolink extends Regex
* This only auto-links URLs with protocol.
*
* @return string that auto-link HTML added
*
* @since 1.1.0
*/
public function autoLinkURLs($tweet = null)
@ -543,6 +559,7 @@ class Autolink extends Regex
$tweet = $this->tweet;
}
$entities = $this->extractor->extractURLWithoutProtocol(false)->extractURLsWithIndices($tweet);
return $this->autoLinkEntities($tweet, $entities);
}
@ -551,6 +568,7 @@ class Autolink extends Regex
* added.
*
* @return string that auto-link HTML added
*
* @since 1.1.0
*/
public function autoLinkCashtags($tweet = null)
@ -559,6 +577,7 @@ class Autolink extends Regex
$tweet = $this->tweet;
}
$entities = $this->extractor->extractCashtagsWithIndices($tweet);
return $this->autoLinkEntities($tweet, $entities);
}
@ -639,10 +658,11 @@ class Autolink extends Regex
}
/**
*
* @param array $entity
* @param string $tweet
*
* @return string
*
* @since 1.1.0
*/
public function linkToHashtag($entity, $tweet = null)
@ -651,13 +671,13 @@ class Autolink extends Regex
$tweet = $this->tweet;
}
$this->target = false;
$attributes = array();
$class = array();
$attributes = [];
$class = [];
$hash = StringUtils::substr($tweet, $entity['indices'][0], 1);
$linkText = $hash . $entity['hashtag'];
$linkText = $hash.$entity['hashtag'];
$attributes['href'] = $this->url_base_hash . $entity['hashtag'] . '?src=hash';
$attributes['title'] = '#' . $entity['hashtag'];
$attributes['href'] = $this->url_base_hash.$entity['hashtag'].'?src=hash';
$attributes['title'] = '#'.$entity['hashtag'];
if (!empty($this->class_hash)) {
$class[] = $this->class_hash;
}
@ -665,32 +685,33 @@ class Autolink extends Regex
$class[] = 'rtl';
}
if (!empty($class)) {
$attributes['class'] = join(' ', $class);
$attributes['class'] = implode(' ', $class);
}
return $this->linkToText($entity, $linkText, $attributes);
}
/**
*
* @param array $entity
*
* @return string
*
* @since 1.1.0
*/
public function linkToMentionAndList($entity)
{
$attributes = array();
$attributes = [];
if (!empty($entity['list_slug'])) {
# Replace the list and username
$linkText = $entity['screen_name'] . $entity['list_slug'];
// Replace the list and username
$linkText = $entity['screen_name'].$entity['list_slug'];
$class = $this->class_list;
$url = $this->url_base_list . $linkText;
$url = $this->url_base_list.$linkText;
} else {
# Replace the username
// Replace the username
$linkText = $entity['screen_name'];
$class = $this->class_user;
$url = $this->url_base_user . $linkText;
$url = $this->url_base_user.$linkText;
}
if (!empty($class)) {
$attributes['class'] = $class;
@ -701,10 +722,11 @@ class Autolink extends Regex
}
/**
*
* @param array $entity
* @param string $tweet
*
* @return string
*
* @since 1.1.0
*/
public function linkToCashtag($entity, $tweet = null)
@ -712,10 +734,10 @@ class Autolink extends Regex
if (is_null($tweet)) {
$tweet = $this->tweet;
}
$attributes = array();
$attributes = [];
$doller = StringUtils::substr($tweet, $entity['indices'][0], 1);
$linkText = $doller . $entity['cashtag'];
$attributes['href'] = $this->url_base_cash . $entity['cashtag'];
$linkText = $doller.$entity['cashtag'];
$attributes['href'] = $this->url_base_cash.$entity['cashtag'];
$attributes['title'] = $linkText;
if (!empty($this->class_cash)) {
$attributes['class'] = $this->class_cash;
@ -725,16 +747,17 @@ class Autolink extends Regex
}
/**
*
* @param array $entity
* @param string $text
* @param array $attributes
*
* @return string
*
* @since 1.1.0
*/
public function linkToText(array $entity, $text, $attributes = array())
public function linkToText(array $entity, $text, $attributes = [])
{
$rel = array();
$rel = [];
if ($this->external) {
$rel[] = 'external';
}
@ -745,23 +768,25 @@ class Autolink extends Regex
$rel[] = 'noopener';
}
if (!empty($rel)) {
$attributes['rel'] = join(' ', $rel);
$attributes['rel'] = implode(' ', $rel);
}
if ($this->target) {
$attributes['target'] = $this->target;
}
$link = '<a';
foreach ($attributes as $key => $val) {
$link .= ' ' . $key . '="' . $this->escapeHTML($val) . '"';
$link .= ' '.$key.'="'.$this->escapeHTML($val).'"';
}
$link .= '>' . $text . '</a>';
$link .= '>'.$text.'</a>';
return $link;
}
/**
* html escape
* html escape.
*
* @param string $text
*
* @return string
*/
protected function escapeHTML($text)

View file

@ -5,16 +5,12 @@
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Mike Cochrane, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
namespace App\Util\Lexer;
use App\Util\Lexer\Regex;
use App\Util\Lexer\StringUtils;
/**
* Twitter Extractor Class
* Twitter Extractor Class.
*
* Parses tweets and extracts URLs, usernames, username/list pairs and
* hashtags.
@ -27,13 +23,11 @@ use App\Util\Lexer\StringUtils;
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Mike Cochrane, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
class Extractor extends Regex
{
/**
* @var boolean
* @var bool
*/
protected $extractURLWithoutProtocol = true;
@ -68,6 +62,7 @@ class Extractor extends Regex
* the extracted elements.
*
* @param string $tweet The tweet to extract.
*
* @return array The elements in the tweet.
*/
public function extract($tweet = null)
@ -75,7 +70,8 @@ class Extractor extends Regex
if (is_null($tweet)) {
$tweet = $this->tweet;
}
return array(
return [
'hashtags' => $this->extractHashtags($tweet),
'urls' => $this->extractURLs($tweet),
'mentions' => $this->extractMentionedUsernames($tweet),
@ -83,13 +79,14 @@ class Extractor extends Regex
'hashtags_with_indices' => $this->extractHashtagsWithIndices($tweet),
'urls_with_indices' => $this->extractURLsWithIndices($tweet),
'mentions_with_indices' => $this->extractMentionedUsernamesWithIndices($tweet),
);
];
}
/**
* Extract URLs, @mentions, lists and #hashtag from a given text/tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array list of extracted entities
*/
public function extractEntitiesWithIndices($tweet = null)
@ -97,12 +94,13 @@ class Extractor extends Regex
if (is_null($tweet)) {
$tweet = $this->tweet;
}
$entities = array();
$entities = [];
$entities = array_merge($entities, $this->extractURLsWithIndices($tweet));
$entities = array_merge($entities, $this->extractHashtagsWithIndices($tweet, false));
$entities = array_merge($entities, $this->extractMentionsOrListsWithIndices($tweet));
$entities = array_merge($entities, $this->extractCashtagsWithIndices($tweet));
$entities = $this->removeOverlappingEntities($entities);
return $entities;
}
@ -110,16 +108,18 @@ class Extractor extends Regex
* Extracts all the hashtags from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The hashtag elements in the tweet.
*/
public function extractHashtags($tweet = null)
{
$hashtagsOnly = array();
$hashtagsOnly = [];
$hashtagsWithIndices = $this->extractHashtagsWithIndices($tweet);
foreach ($hashtagsWithIndices as $hashtagWithIndex) {
$hashtagsOnly[] = $hashtagWithIndex['hashtag'];
}
return $hashtagsOnly;
}
@ -127,16 +127,18 @@ class Extractor extends Regex
* Extracts all the cashtags from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The cashtag elements in the tweet.
*/
public function extractCashtags($tweet = null)
{
$cashtagsOnly = array();
$cashtagsOnly = [];
$cashtagsWithIndices = $this->extractCashtagsWithIndices($tweet);
foreach ($cashtagsWithIndices as $cashtagWithIndex) {
$cashtagsOnly[] = $cashtagWithIndex['cashtag'];
}
return $cashtagsOnly;
}
@ -144,16 +146,18 @@ class Extractor extends Regex
* Extracts all the URLs from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The URL elements in the tweet.
*/
public function extractURLs($tweet = null)
{
$urlsOnly = array();
$urlsOnly = [];
$urlsWithIndices = $this->extractURLsWithIndices($tweet);
foreach ($urlsWithIndices as $urlWithIndex) {
$urlsOnly[] = $urlWithIndex['url'];
}
return $urlsOnly;
}
@ -163,20 +167,22 @@ class Extractor extends Regex
* A mention is an occurrence of a username anywhere in a tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The usernames elements in the tweet.
*/
public function extractMentionedScreennames($tweet = null)
{
$usernamesOnly = array();
$usernamesOnly = [];
$mentionsWithIndices = $this->extractMentionsOrListsWithIndices($tweet);
foreach ($mentionsWithIndices as $mentionWithIndex) {
$screen_name = mb_strtolower($mentionWithIndex['screen_name']);
if (empty($screen_name) OR in_array($screen_name, $usernamesOnly)) {
if (empty($screen_name) or in_array($screen_name, $usernamesOnly)) {
continue;
}
$usernamesOnly[] = $screen_name;
}
return $usernamesOnly;
}
@ -186,11 +192,13 @@ class Extractor extends Regex
* A mention is an occurrence of a username anywhere in a tweet.
*
* @return array The usernames elements in the tweet.
*
* @deprecated since version 1.1.0
*/
public function extractMentionedUsernames($tweet)
{
$this->tweet = $tweet;
return $this->extractMentionedScreennames($tweet);
}
@ -200,6 +208,7 @@ class Extractor extends Regex
* A reply is an occurrence of a username at the beginning of a tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The usernames replied to in a tweet.
*/
public function extractReplyScreenname($tweet = null)
@ -208,10 +217,11 @@ class Extractor extends Regex
$tweet = $this->tweet;
}
$matched = preg_match(self::$patterns['valid_reply'], $tweet, $matches);
# Check username ending in
// Check username ending in
if ($matched && preg_match(self::$patterns['end_mention_match'], $matches[2])) {
$matched = false;
}
return $matched ? $matches[1] : null;
}
@ -221,6 +231,7 @@ class Extractor extends Regex
* A reply is an occurrence of a username at the beginning of a tweet.
*
* @return array The usernames replied to in a tweet.
*
* @deprecated since version 1.1.0
*/
public function extractRepliedUsernames()
@ -232,7 +243,8 @@ class Extractor extends Regex
* Extracts all the hashtags and the indices they occur at from the tweet.
*
* @param string $tweet The tweet to extract.
* @param boolean $checkUrlOverlap if true, check if extracted hashtags overlap URLs and remove overlapping ones
* @param bool $checkUrlOverlap if true, check if extracted hashtags overlap URLs and remove overlapping ones
*
* @return array The hashtag elements in the tweet.
*/
public function extractHashtagsWithIndices($tweet = null, $checkUrlOverlap = true)
@ -242,36 +254,36 @@ class Extractor extends Regex
}
if (!preg_match('/[#]/iu', $tweet)) {
return array();
return [];
}
preg_match_all(self::$patterns['valid_hashtag'], $tweet, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$tags = array();
$tags = [];
foreach ($matches as $match) {
list($all, $before, $hash, $hashtag, $outer) = array_pad($match, 3, array('', 0));
list($all, $before, $hash, $hashtag, $outer) = array_pad($match, 3, ['', 0]);
$start_position = $hash[1] > 0 ? StringUtils::strlen(substr($tweet, 0, $hash[1])) : $hash[1];
$end_position = $start_position + StringUtils::strlen($hash[0] . $hashtag[0]);
$end_position = $start_position + StringUtils::strlen($hash[0].$hashtag[0]);
if (preg_match(self::$patterns['end_hashtag_match'], $outer[0])) {
continue;
}
$tags[] = array(
$tags[] = [
'hashtag' => $hashtag[0],
'indices' => array($start_position, $end_position)
);
'indices' => [$start_position, $end_position],
];
}
if (!$checkUrlOverlap) {
return $tags;
}
# check url overlap
// check url overlap
$urls = $this->extractURLsWithIndices($tweet);
$entities = $this->removeOverlappingEntities(array_merge($tags, $urls));
$validTags = array();
$validTags = [];
foreach ($entities as $entity) {
if (empty($entity['hashtag'])) {
continue;
@ -286,6 +298,7 @@ class Extractor extends Regex
* Extracts all the cashtags and the indices they occur at from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The cashtag elements in the tweet.
*/
public function extractCashtagsWithIndices($tweet = null)
@ -295,25 +308,25 @@ class Extractor extends Regex
}
if (!preg_match('/\$/iu', $tweet)) {
return array();
return [];
}
preg_match_all(self::$patterns['valid_cashtag'], $tweet, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$tags = array();
$tags = [];
foreach ($matches as $match) {
list($all, $before, $dollar, $cash_text, $outer) = array_pad($match, 3, array('', 0));
list($all, $before, $dollar, $cash_text, $outer) = array_pad($match, 3, ['', 0]);
$start_position = $dollar[1] > 0 ? StringUtils::strlen(substr($tweet, 0, $dollar[1])) : $dollar[1];
$end_position = $start_position + StringUtils::strlen($dollar[0] . $cash_text[0]);
$end_position = $start_position + StringUtils::strlen($dollar[0].$cash_text[0]);
if (preg_match(self::$patterns['end_hashtag_match'], $outer[0])) {
continue;
}
$tags[] = array(
$tags[] = [
'cashtag' => $cash_text[0],
'indices' => array($start_position, $end_position)
);
'indices' => [$start_position, $end_position],
];
}
return $tags;
@ -323,6 +336,7 @@ class Extractor extends Regex
* Extracts all the URLs and the indices they occur at from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The URLs elements in the tweet.
*/
public function extractURLsWithIndices($tweet = null)
@ -333,14 +347,14 @@ class Extractor extends Regex
$needle = $this->extractURLWithoutProtocol() ? '.' : ':';
if (strpos($tweet, $needle) === false) {
return array();
return [];
}
$urls = array();
$urls = [];
preg_match_all(self::$patterns['valid_url'], $tweet, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
foreach ($matches as $match) {
list($all, $before, $url, $protocol, $domain, $port, $path, $query) = array_pad($match, 8, array(''));
list($all, $before, $url, $protocol, $domain, $port, $path, $query) = array_pad($match, 8, ['']);
$start_position = $url[1] > 0 ? StringUtils::strlen(substr($tweet, 0, $url[1])) : $url[1];
$end_position = $start_position + StringUtils::strlen($url[0]);
@ -364,13 +378,13 @@ class Extractor extends Regex
$ascii_end_position = 0;
if (preg_match(self::$patterns['valid_ascii_domain'], $domain, $asciiDomain)) {
$asciiDomain[0] = preg_replace('/' . preg_quote($domain, '/') . '/u', $asciiDomain[0], $url);
$asciiDomain[0] = preg_replace('/'.preg_quote($domain, '/').'/u', $asciiDomain[0], $url);
$ascii_start_position = StringUtils::strpos($domain, $asciiDomain[0], $ascii_end_position);
$ascii_end_position = $ascii_start_position + StringUtils::strlen($asciiDomain[0]);
$last_url = array(
$last_url = [
'url' => $asciiDomain[0],
'indices' => array($start_position + $ascii_start_position, $start_position + $ascii_end_position),
);
'indices' => [$start_position + $ascii_start_position, $start_position + $ascii_end_position],
];
if (!empty($path)
|| preg_match(self::$patterns['valid_special_short_domain'], $asciiDomain[0])
|| !preg_match(self::$patterns['invalid_short_domain'], $asciiDomain[0])) {
@ -386,7 +400,7 @@ class Extractor extends Regex
// $last_url only contains domain. Need to add path and query if they exist.
if (!empty($path)) {
// last_url was not added. Add it to urls here.
$last_url['url'] = preg_replace('/' . preg_quote($domain, '/') . '/u', $last_url['url'], $url);
$last_url['url'] = preg_replace('/'.preg_quote($domain, '/').'/u', $last_url['url'], $url);
$last_url['indices'][1] = $end_position;
}
} else {
@ -395,10 +409,10 @@ class Extractor extends Regex
$url = $tcoUrlMatches[0];
$end_position = $start_position + StringUtils::strlen($url);
}
$urls[] = array(
$urls[] = [
'url' => $url,
'indices' => array($start_position, $end_position),
);
'indices' => [$start_position, $end_position],
];
}
}
@ -409,6 +423,7 @@ class Extractor extends Regex
* Extracts all the usernames and the indices they occur at from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The username elements in the tweet.
*/
public function extractMentionedScreennamesWithIndices($tweet = null)
@ -417,7 +432,7 @@ class Extractor extends Regex
$tweet = $this->tweet;
}
$usernamesOnly = array();
$usernamesOnly = [];
$mentions = $this->extractMentionsOrListsWithIndices($tweet);
foreach ($mentions as $mention) {
if (isset($mention['list_slug'])) {
@ -425,6 +440,7 @@ class Extractor extends Regex
}
$usernamesOnly[] = $mention;
}
return $usernamesOnly;
}
@ -432,6 +448,7 @@ class Extractor extends Regex
* Extracts all the usernames and the indices they occur at from the tweet.
*
* @return array The username elements in the tweet.
*
* @deprecated since version 1.1.0
*/
public function extractMentionedUsernamesWithIndices()
@ -443,6 +460,7 @@ class Extractor extends Regex
* Extracts all the usernames and the indices they occur at from the tweet.
*
* @param string $tweet The tweet to extract.
*
* @return array The username elements in the tweet.
*/
public function extractMentionsOrListsWithIndices($tweet = null)
@ -452,21 +470,21 @@ class Extractor extends Regex
}
if (!preg_match('/[@]/iu', $tweet)) {
return array();
return [];
}
preg_match_all(self::$patterns['valid_mentions_or_lists'], $tweet, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$results = array();
$results = [];
foreach ($matches as $match) {
list($all, $before, $at, $username, $list_slug, $outer) = array_pad($match, 6, array('', 0));
list($all, $before, $at, $username, $list_slug, $outer) = array_pad($match, 6, ['', 0]);
$start_position = $at[1] > 0 ? StringUtils::strlen(substr($tweet, 0, $at[1])) : $at[1];
$end_position = $start_position + StringUtils::strlen($at[0]) + StringUtils::strlen($username[0]);
$entity = array(
$entity = [
'screen_name' => $username[0],
'list_slug' => $list_slug[0],
'indices' => array($start_position, $end_position),
);
'indices' => [$start_position, $end_position],
];
if (preg_match(self::$patterns['end_mention_match'], $outer[0])) {
continue;
@ -486,6 +504,7 @@ class Extractor extends Regex
* Extracts all the usernames and the indices they occur at from the tweet.
*
* @return array The username elements in the tweet.
*
* @deprecated since version 1.1.0
*/
public function extractMentionedUsernamesOrListsWithIndices()
@ -494,9 +513,10 @@ class Extractor extends Regex
}
/**
* setter/getter for extractURLWithoutProtocol
* setter/getter for extractURLWithoutProtocol.
*
* @param bool $flag
*
* @param boolean $flag
* @return Extractor
*/
public function extractURLWithoutProtocol($flag = null)
@ -505,6 +525,7 @@ class Extractor extends Regex
return $this->extractURLWithoutProtocol;
}
$this->extractURLWithoutProtocol = (bool) $flag;
return $this;
}
@ -513,12 +534,13 @@ class Extractor extends Regex
* This returns a new array with no overlapping entities.
*
* @param array $entities
*
* @return array
*/
public function removeOverlappingEntities($entities)
{
$result = array();
usort($entities, array($this, 'sortEntites'));
$result = [];
usort($entities, [$this, 'sortEntites']);
$prev = null;
foreach ($entities as $entity) {
@ -528,14 +550,16 @@ class Extractor extends Regex
$prev = $entity;
$result[] = $entity;
}
return $result;
}
/**
* sort by entity start index
* sort by entity start index.
*
* @param array $a
* @param array $b
*
* @return int
*/
protected function sortEntites($a, $b)
@ -543,6 +567,7 @@ class Extractor extends Regex
if ($a['indices'][0] == $b['indices'][0]) {
return 0;
}
return ($a['indices'][0] < $b['indices'][0]) ? -1 : 1;
}
}

View file

@ -2,8 +2,8 @@
namespace App\Util\Lexer;
class Hashtag {
class Hashtag
{
public static function getHashtags($status)
{
$hashtags = false;
@ -12,25 +12,26 @@ class Hashtag {
$res = array_count_values($matches[0]);
$hashtags = array_keys($res);
}
return $hashtags;
}
public static function replaceHashtagsWithLinks($status)
{
$hashtags = self::getHashtags($status);
if(!$hashtags) { return false; }
if (!$hashtags) {
return false;
}
$rendered = $status;
foreach($hashtags as $hashtag) {
foreach ($hashtags as $hashtag) {
$tag = substr($hashtag, 1);
$link = config('routes.hashtag.search') . $tag;
$link = config('routes.hashtag.search').$tag;
$href = "<a href='{$link}' class='mention hashtag status-link' rel='noopener'>{$hashtag}</a>";
$rendered = str_replace($hashtag, $href, $rendered);
}
return $rendered;
}
}

View file

@ -4,16 +4,12 @@
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
namespace App\Util\Lexer;
use App\Util\Lexer\Regex;
use App\Util\Lexer\StringUtils;
/**
* Twitter HitHighlighter Class
* Twitter HitHighlighter Class.
*
* Performs "hit highlighting" on tweets that have been auto-linked already.
* Useful with the results returned from the search API.
@ -25,11 +21,9 @@ use App\Util\Lexer\StringUtils;
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
class HitHighlighter extends Regex
{
/**
* The tag to surround hits with.
*
@ -96,6 +90,7 @@ class HitHighlighter extends Regex
public function setTag($v)
{
$this->tag = $v;
return $this;
}
@ -119,8 +114,8 @@ class HitHighlighter extends Regex
return $tweet;
}
$highlightTweet = '';
$tags = array('<' . $this->tag . '>', '</' . $this->tag . '>');
# Check whether we can simply replace or whether we need to chunk...
$tags = ['<'.$this->tag.'>', '</'.$this->tag.'>'];
// Check whether we can simply replace or whether we need to chunk...
if (strpos($tweet, '<') === false) {
$ti = 0; // tag increment (for added tags)
$highlightTweet = $tweet;
@ -137,12 +132,12 @@ class HitHighlighter extends Regex
$chunk_cursor = 0;
$offset = 0;
$start_in_chunk = false;
# Flatten the multidimensional hits array:
$hits_flat = array();
// Flatten the multidimensional hits array:
$hits_flat = [];
foreach ($hits as $hit) {
$hits_flat = array_merge($hits_flat, $hit);
}
# Loop over the hit indices:
// Loop over the hit indices:
for ($index = 0; $index < count($hits_flat); $index++) {
$hit = $hits_flat[$index];
$tag = $tags[$index % 2];
@ -154,7 +149,7 @@ class HitHighlighter extends Regex
$placed = true;
}
if (isset($chunks[$chunk_index + 1])) {
$highlightTweet .= '<' . $chunks[$chunk_index + 1] . '>';
$highlightTweet .= '<'.$chunks[$chunk_index + 1].'>';
}
$offset += StringUtils::strlen($chunk);
$chunk_cursor = 0;
@ -164,12 +159,12 @@ class HitHighlighter extends Regex
}
if (!$placed && $chunk !== null) {
$hit_spot = $hit - $offset;
$highlightTweet .= StringUtils::substr($chunk, $chunk_cursor, $hit_spot - $chunk_cursor) . $tag;
$highlightTweet .= StringUtils::substr($chunk, $chunk_cursor, $hit_spot - $chunk_cursor).$tag;
$chunk_cursor = $hit_spot;
$start_in_chunk = ($index % 2 === 0);
$placed = true;
}
# Ultimate fallback - hits that run off the end get a closing tag:
// Ultimate fallback - hits that run off the end get a closing tag:
if (!$placed) {
$highlightTweet .= $tag;
}
@ -179,10 +174,11 @@ class HitHighlighter extends Regex
$highlightTweet .= StringUtils::substr($chunk, $chunk_cursor);
}
for ($index = $chunk_index + 1; $index < count($chunks); $index++) {
$highlightTweet .= ($index % 2 === 0 ? $chunks[$index] : '<' . $chunks[$index] . '>');
$highlightTweet .= ($index % 2 === 0 ? $chunks[$index] : '<'.$chunks[$index].'>');
}
}
}
return $highlightTweet;
}
@ -193,6 +189,7 @@ class HitHighlighter extends Regex
* for the highlighting.
*
* @return string The hit highlighted tweet.
*
* @deprecated since version 1.1.0
*/
public function addHitHighlighting(array $hits)

View file

@ -6,15 +6,12 @@
* @author Takashi Nojima
* @copyright Copyright 2014 Mike Cochrane, Nick Pope, Takashi Nojima
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
namespace App\Util\Lexer;
use App\Util\Lexer\Autolink;
/**
* Twitter LooseAutolink Class
* Twitter LooseAutolink Class.
*
* Parses tweets and generates HTML anchor tags around URLs, usernames,
* username/list pairs and hashtags.
@ -28,18 +25,19 @@ use App\Util\Lexer\Autolink;
* @author Takashi Nojima
* @copyright Copyright 2014 Mike Cochrane, Nick Pope, Takashi Nojima
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*
* @since 1.8.0
* @deprecated since version 1.9.0
*/
class LooseAutolink extends Autolink
{
/**
* Auto-link hashtags, URLs, usernames and lists.
*
* @param string The tweet to be converted
*
* @return string that auto-link HTML added
*
* @deprecated since version 1.9.0
*/
public function autoLink($tweet = null)
@ -47,6 +45,7 @@ class LooseAutolink extends Autolink
if (!is_null($tweet)) {
$this->tweet = $tweet;
}
return $this->addLinks();
}
@ -62,6 +61,7 @@ class LooseAutolink extends Autolink
if (!is_null($tweet)) {
$this->tweet = $tweet;
}
return $this->addLinksToUsernamesAndLists();
}
@ -76,6 +76,7 @@ class LooseAutolink extends Autolink
if (!is_null($tweet)) {
$this->tweet = $tweet;
}
return $this->addLinksToHashtags();
}
@ -91,6 +92,7 @@ class LooseAutolink extends Autolink
if (!is_null($tweet)) {
$this->tweet = $tweet;
}
return $this->addLinksToURLs();
}
@ -105,6 +107,7 @@ class LooseAutolink extends Autolink
if (!is_null($tweet)) {
$this->tweet = $tweet;
}
return $this->addLinksToCashtags();
}
@ -112,6 +115,7 @@ class LooseAutolink extends Autolink
* Adds links to all elements in the tweet.
*
* @return string The modified tweet.
*
* @deprecated since version 1.9.0
*/
public function addLinks()
@ -123,6 +127,7 @@ class LooseAutolink extends Autolink
$this->tweet = $this->addLinksToUsernamesAndLists();
$modified = $this->tweet;
$this->tweet = $original;
return $modified;
}
@ -135,7 +140,7 @@ class LooseAutolink extends Autolink
{
return preg_replace_callback(
self::$patterns['valid_hashtag'],
array($this, '_addLinksToHashtags'),
[$this, '_addLinksToHashtags'],
$this->tweet
);
}
@ -149,7 +154,7 @@ class LooseAutolink extends Autolink
{
return preg_replace_callback(
self::$patterns['valid_cashtag'],
array($this, '_addLinksToCashtags'),
[$this, '_addLinksToCashtags'],
$this->tweet
);
}
@ -161,7 +166,7 @@ class LooseAutolink extends Autolink
*/
public function addLinksToURLs()
{
return preg_replace_callback(self::$patterns['valid_url'], array($this, '_addLinksToURLs'), $this->tweet);
return preg_replace_callback(self::$patterns['valid_url'], [$this, '_addLinksToURLs'], $this->tweet);
}
/**
@ -173,7 +178,7 @@ class LooseAutolink extends Autolink
{
return preg_replace_callback(
self::$patterns['valid_mentions_or_lists'],
array($this, '_addLinksToUsernamesAndLists'),
[$this, '_addLinksToUsernamesAndLists'],
$this->tweet
);
}
@ -188,16 +193,17 @@ class LooseAutolink extends Autolink
* @param string $element The tweet element to wrap.
*
* @return string The tweet element with a link applied.
*
* @deprecated since version 1.1.0
*/
protected function wrap($url, $class, $element)
{
$link = '<a';
if ($class) {
$link .= ' class="' . $class . '"';
$link .= ' class="'.$class.'"';
}
$link .= ' href="' . $url . '"';
$rel = array();
$link .= ' href="'.$url.'"';
$rel = [];
if ($this->external) {
$rel[] = 'external';
}
@ -205,12 +211,13 @@ class LooseAutolink extends Autolink
$rel[] = 'nofollow';
}
if (!empty($rel)) {
$link .= ' rel="' . implode(' ', $rel) . '"';
$link .= ' rel="'.implode(' ', $rel).'"';
}
if ($this->target) {
$link .= ' target="' . $this->target . '"';
$link .= ' target="'.$this->target.'"';
}
$link .= '>' . $element . '</a>';
$link .= '>'.$element.'</a>';
return $link;
}
@ -229,12 +236,12 @@ class LooseAutolink extends Autolink
{
$title = preg_replace('//u', '#', $element);
$link = '<a';
$link .= ' href="' . $url . '"';
$link .= ' title="' . $title . '"';
$link .= ' href="'.$url.'"';
$link .= ' title="'.$title.'"';
if ($class) {
$link .= ' class="' . $class . '"';
$link .= ' class="'.$class.'"';
}
$rel = array();
$rel = [];
if ($this->external) {
$rel[] = 'external';
}
@ -242,12 +249,13 @@ class LooseAutolink extends Autolink
$rel[] = 'nofollow';
}
if (!empty($rel)) {
$link .= ' rel="' . implode(' ', $rel) . '"';
$link .= ' rel="'.implode(' ', $rel).'"';
}
if ($this->target) {
$link .= ' target="' . $this->target . '"';
$link .= ' target="'.$this->target.'"';
}
$link .= '>' . $element . '</a>';
$link .= '>'.$element.'</a>';
return $link;
}
@ -255,7 +263,9 @@ class LooseAutolink extends Autolink
* Callback used by the method that adds links to hashtags.
*
* @see addLinksToHashtags()
*
* @param array $matches The regular expression matches.
*
* @return string The link-wrapped hashtag.
*/
protected function _addLinksToHashtags($matches)
@ -266,13 +276,14 @@ class LooseAutolink extends Autolink
return $all;
}
$replacement = $before;
$element = $hash . $tag;
$url = $this->url_base_hash . $tag;
$element = $hash.$tag;
$url = $this->url_base_hash.$tag;
$class_hash = $this->class_hash;
if (preg_match(self::$patterns['rtl_chars'], $element)) {
$class_hash .= ' rtl';
}
$replacement .= $this->wrapHash($url, $class_hash, $element);
return $replacement;
}
@ -280,7 +291,9 @@ class LooseAutolink extends Autolink
* Callback used by the method that adds links to cashtags.
*
* @see addLinksToCashtags()
*
* @param array $matches The regular expression matches.
*
* @return string The link-wrapped cashtag.
*/
protected function _addLinksToCashtags($matches)
@ -291,9 +304,10 @@ class LooseAutolink extends Autolink
return $all;
}
$replacement = $before;
$element = $cash . $tag;
$url = $this->url_base_cash . $tag;
$element = $cash.$tag;
$url = $this->url_base_cash.$tag;
$replacement .= $this->wrapHash($url, $this->class_cash, $element);
return $replacement;
}
@ -301,7 +315,9 @@ class LooseAutolink extends Autolink
* Callback used by the method that adds links to URLs.
*
* @see addLinksToURLs()
*
* @param array $matches The regular expression matches.
*
* @return string The link-wrapped URL.
*/
protected function _addLinksToURLs($matches)
@ -311,38 +327,41 @@ class LooseAutolink extends Autolink
if (!$protocol) {
return $all;
}
return $before . $this->wrap($url, $this->class_url, $url);
return $before.$this->wrap($url, $this->class_url, $url);
}
/**
* Callback used by the method that adds links to username/list pairs.
*
* @see addLinksToUsernamesAndLists()
*
* @param array $matches The regular expression matches.
*
* @return string The link-wrapped username/list pair.
*/
protected function _addLinksToUsernamesAndLists($matches)
{
list($all, $before, $at, $username, $slash_listname, $after) = array_pad($matches, 6, '');
# If $after is not empty, there is an invalid character.
// If $after is not empty, there is an invalid character.
if (!empty($slash_listname)) {
# Replace the list and username
$element = $username . $slash_listname;
// Replace the list and username
$element = $username.$slash_listname;
$class = $this->class_list;
$url = $this->url_base_list . $element;
$url = $this->url_base_list.$element;
} else {
if (preg_match(self::$patterns['end_mention_match'], $after)) {
return $all;
}
# Replace the username
// Replace the username
$element = $username;
$class = $this->class_user;
$url = $this->url_base_user . $element;
$url = $this->url_base_user.$element;
}
# XXX: Due to use of preg_replace_callback() for multiple replacements in a
# single tweet and also as only the match is replaced and we have to
# use a look-ahead for $after because there is no equivalent for the
# $' (dollar apostrophe) global from Ruby, we MUST NOT append $after.
return $before . $at . $this->wrap($url, $class, $element);
// XXX: Due to use of preg_replace_callback() for multiple replacements in a
// single tweet and also as only the match is replaced and we have to
// use a look-ahead for $after because there is no equivalent for the
// $' (dollar apostrophe) global from Ruby, we MUST NOT append $after.
return $before.$at.$this->wrap($url, $class, $element);
}
}

View file

@ -2,17 +2,18 @@
namespace App\Util\Lexer;
class Nickname {
class Nickname
{
public static function normalizeProfileUrl($url)
{
if(starts_with($url, 'acct:')) {
if (starts_with($url, 'acct:')) {
$url = str_replace('acct:', '', $url);
}
if(!str_contains($url, '@') && filter_var($url, FILTER_VALIDATE_URL)) {
if (!str_contains($url, '@') && filter_var($url, FILTER_VALIDATE_URL)) {
$parsed = parse_url($url);
$username = str_replace(['/','\\','@'], '', $parsed['path']);
$username = str_replace(['/', '\\', '@'], '', $parsed['path']);
return ['domain' => $parsed['host'], 'username' => $username];
}
$parts = explode('@', $url);
@ -22,21 +23,20 @@ class Nickname {
foreach ($parts as $part) {
// skip empty array slices
if(empty($part)) {
if (empty($part)) {
continue;
}
// if slice contains . assume its a domain
if(str_contains($part, '.')) {
if (str_contains($part, '.')) {
$domain = filter_var($part, FILTER_VALIDATE_URL) ?
parse_url($part, PHP_URL_HOST) :
$part;
} else {
$username = $part;
}
}
return ['domain' => $domain, 'username' => $username];
}
}

View file

@ -2,35 +2,38 @@
namespace App\Util\Lexer;
class PrettyNumber {
class PrettyNumber
{
public static function convert($expression)
{
$abbrevs = array(12 => "T", 9 => "B", 6 => "M", 3 => "K", 0 => "");
foreach($abbrevs as $exponent => $abbrev) {
if($expression >= pow(10, $exponent)) {
$abbrevs = [12 => 'T', 9 => 'B', 6 => 'M', 3 => 'K', 0 => ''];
foreach ($abbrevs as $exponent => $abbrev) {
if ($expression >= pow(10, $exponent)) {
$display_num = $expression / pow(10, $exponent);
$num = number_format($display_num,0) . $abbrev;
$num = number_format($display_num, 0).$abbrev;
return $num;
}
}
return $expression;
}
public static function size($expression, $kb = false)
{
if($kb) {
if ($kb) {
$expression = $expression * 1024;
}
$size = intval($expression);
$precision = 0;
$short = true;
$units = $short ?
['B','k','M','G','T','P','E','Z','Y'] :
['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
for($i = 0; ($size / 1024) > 0.9; $i++, $size /= 1024) {}
['B', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] :
['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
for ($i = 0; ($size / 1024) > 0.9; $i++, $size /= 1024) {
}
$res = round($size, $precision).$units[$i];
return $res;
}
}

File diff suppressed because one or more lines are too long

View file

@ -2,180 +2,179 @@
namespace App\Util\Lexer;
class RestrictedNames {
static $blacklist = [
"about",
"abuse",
"administrator",
"app",
"autoconfig",
"blog",
"broadcasthost",
"community",
"contact",
"contact-us",
"contact_us",
"copyright",
"d",
"dashboard",
"dev",
"developer",
"developers",
"discover",
"discovers",
"doc",
"docs",
"download",
"domainadmin",
"domainadministrator",
"email",
"errors",
"events",
"example",
"faq",
"faqs",
"features",
"ftp",
"guest",
"guests",
"help",
"hostmaster",
"hostmaster",
"image",
"images",
"imap",
"img",
"info",
"info",
"is",
"isatap",
"it",
"localdomain",
"localhost",
"mail",
"mailer-daemon",
"mailerdaemon",
"marketing",
"me",
"media",
"mis",
"mx",
"new",
"news",
"news",
"no-reply",
"nobody",
"noc",
"noreply",
"ns0",
"ns1",
"ns2",
"ns3",
"ns4",
"ns5",
"ns6",
"ns7",
"ns8",
"ns9",
"owner",
"pop",
"pop3",
"postmaster",
"pricing",
"privacy",
"root",
"sales",
"security",
"signin",
"signout",
"smtp",
"src",
"ssladmin",
"ssladministrator",
"sslwebmaster",
"status",
"support",
"support",
"sys",
"sysadmin",
"system",
"terms",
"tutorial",
"tutorials",
"usenet",
"uucp",
"webmaster",
"wpad",
"www"
class RestrictedNames
{
public static $blacklist = [
'about',
'abuse',
'administrator',
'app',
'autoconfig',
'blog',
'broadcasthost',
'community',
'contact',
'contact-us',
'contact_us',
'copyright',
'd',
'dashboard',
'dev',
'developer',
'developers',
'discover',
'discovers',
'doc',
'docs',
'download',
'domainadmin',
'domainadministrator',
'email',
'errors',
'events',
'example',
'faq',
'faqs',
'features',
'ftp',
'guest',
'guests',
'help',
'hostmaster',
'hostmaster',
'image',
'images',
'imap',
'img',
'info',
'info',
'is',
'isatap',
'it',
'localdomain',
'localhost',
'mail',
'mailer-daemon',
'mailerdaemon',
'marketing',
'me',
'media',
'mis',
'mx',
'new',
'news',
'news',
'no-reply',
'nobody',
'noc',
'noreply',
'ns0',
'ns1',
'ns2',
'ns3',
'ns4',
'ns5',
'ns6',
'ns7',
'ns8',
'ns9',
'owner',
'pop',
'pop3',
'postmaster',
'pricing',
'privacy',
'root',
'sales',
'security',
'signin',
'signout',
'smtp',
'src',
'ssladmin',
'ssladministrator',
'sslwebmaster',
'status',
'support',
'support',
'sys',
'sysadmin',
'system',
'terms',
'tutorial',
'tutorials',
'usenet',
'uucp',
'webmaster',
'wpad',
'www',
];
static $reserved = [
public static $reserved = [
// Reserved for instance admin
"admin",
'admin',
// Static Assets
"assets",
"storage",
'assets',
'storage',
// Laravel Horizon
"horizon",
'horizon',
// Reserved routes
"account",
"api",
"auth",
"css",
"c",
"i",
"dashboard",
"deck",
"discover",
"docs",
"fonts",
"home",
"img",
"js",
"login",
"logout",
"media",
"p",
"password",
"report",
"reports",
"search",
"settings",
"statuses",
"site",
"sites",
"timeline",
"timelines",
"tour",
"user",
"users",
"vendor",
"400",
"401",
"403",
"404",
"500",
"503",
"504",
'account',
'api',
'auth',
'css',
'c',
'i',
'dashboard',
'deck',
'discover',
'docs',
'fonts',
'home',
'img',
'js',
'login',
'logout',
'media',
'p',
'password',
'report',
'reports',
'search',
'settings',
'statuses',
'site',
'sites',
'timeline',
'timelines',
'tour',
'user',
'users',
'vendor',
'400',
'401',
'403',
'404',
'500',
'503',
'504',
];
public static function get()
{
$reserved = $blacklist = [];
if(true == config('pixelfed.restricted_names.use_blacklist')) {
if (true == config('pixelfed.restricted_names.use_blacklist')) {
$blacklist = self::$blacklist;
}
if(true == config('pixelfed.restricted_names.reserved_routes')) {
if (true == config('pixelfed.restricted_names.reserved_routes')) {
$reserved = self::$reserved;
}
return array_merge($blacklist, $reserved);
}
}

View file

@ -4,29 +4,27 @@
* @author Takashi Nojima
* @copyright Copyright 2014, Takashi Nojima
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
namespace App\Util\Lexer;
/**
* String utility
* String utility.
*
* @author Takashi Nojima
* @copyright Copyright 2014, Takashi Nojima
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter
*/
class StringUtils
{
/**
* alias of mb_substr
* alias of mb_substr.
*
* @param string $str
* @param integer $start
* @param integer $length
* @param int $start
* @param int $length
* @param string $encoding
*
* @return string
*/
public static function substr($str, $start, $length = null, $encoding = 'UTF-8')
@ -35,15 +33,17 @@ class StringUtils
// for PHP <= 5.4.7
$length = mb_strlen($str, $encoding);
}
return mb_substr($str, $start, $length, $encoding);
}
/**
* alias of mb_strlen
* alias of mb_strlen.
*
* @param string $str
* @param string $encoding
* @return integer
*
* @return int
*/
public static function strlen($str, $encoding = 'UTF-8')
{
@ -51,13 +51,14 @@ class StringUtils
}
/**
* alias of mb_strpos
* alias of mb_strpos.
*
* @param string $haystack
* @param string $needle
* @param integer $offset
* @param int $offset
* @param string $encoding
* @return integer
*
* @return int
*/
public static function strpos($haystack, $needle, $offset = 0, $encoding = 'UTF-8')
{
@ -97,8 +98,10 @@ class StringUtils
$suffixOffset = $start + $length;
$suffixLength = $string_length - $start - $length;
return static::substr($string, 0, $start, $encoding) . $replacement . static::substr($string, $suffixOffset, $suffixLength, $encoding);
return static::substr($string, 0, $start, $encoding).$replacement.static::substr($string, $suffixOffset, $suffixLength, $encoding);
}
return (is_null($length) === true) ? substr_replace($string, $replacement, $start) : substr_replace($string, $replacement, $start, $length);
}
}

View file

@ -4,17 +4,12 @@
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
namespace App\Util\Lexer;
use App\Util\Lexer\Regex;
use App\Util\Lexer\Extractor;
use App\Util\Lexer\StringUtils;
/**
* Twitter Validator Class
* Twitter Validator Class.
*
* Performs "validation" on tweets.
*
@ -25,11 +20,9 @@ use App\Util\Lexer\StringUtils;
* @author Nick Pope <nick@nickpope.me.uk>
* @copyright Copyright © 2010, Nick Pope
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
* @package Twitter.Text
*/
class Validator extends Regex
{
/**
* The maximum length of a tweet.
*
@ -38,21 +31,20 @@ class Validator extends Regex
const MAX_LENGTH = 140;
/**
* The length of a short URL beginning with http:
* The length of a short URL beginning with http:.
*
* @var int
*/
protected $short_url_length = 23;
/**
* The length of a short URL beginning with http:
* The length of a short URL beginning with http:.
*
* @var int
*/
protected $short_url_length_https = 23;
/**
*
* @var Extractor
*/
protected $extractor = null;
@ -87,10 +79,12 @@ class Validator extends Regex
}
/**
* Setup short URL length from Twitter API /help/configuration response
* Setup short URL length from Twitter API /help/configuration response.
*
* @param mixed $config
*
* @return Validator
*
* @link https://dev.twitter.com/docs/api/1/get/help/configuration
*/
public function setConfiguration($config)
@ -117,19 +111,21 @@ class Validator extends Regex
}
/**
* Set the length of a short URL beginning with http:
* Set the length of a short URL beginning with http:.
*
* @param mixed $length
*
* @return Validator
*/
public function setShortUrlLength($length)
{
$this->short_url_length = intval($length);
return $this;
}
/**
* Get the length of a short URL beginning with http:
* Get the length of a short URL beginning with http:.
*
* @return int
*/
@ -139,19 +135,21 @@ class Validator extends Regex
}
/**
* Set the length of a short URL beginning with https:
* Set the length of a short URL beginning with https:.
*
* @param mixed $length
*
* @return Validator
*/
public function setShortUrlLengthHttps($length)
{
$this->short_url_length_https = intval($length);
return $this;
}
/**
* Get the length of a short URL beginning with https:
* Get the length of a short URL beginning with https:.
*
* @return int
*/
@ -164,7 +162,8 @@ class Validator extends Regex
* Check whether a tweet is valid.
*
* @param string $tweet The tweet to validate.
* @return boolean Whether the tweet is valid.
*
* @return bool Whether the tweet is valid.
*/
public function isValidTweetText($tweet = null)
{
@ -181,13 +180,15 @@ class Validator extends Regex
if (preg_match(self::$patterns['invalid_characters'], $tweet)) {
return false;
}
return true;
}
/**
* Check whether a tweet is valid.
*
* @return boolean Whether the tweet is valid.
* @return bool Whether the tweet is valid.
*
* @deprecated since version 1.1.0
*/
public function validateTweet()
@ -199,7 +200,8 @@ class Validator extends Regex
* Check whether a username is valid.
*
* @param string $username The username to validate.
* @return boolean Whether the username is valid.
*
* @return bool Whether the username is valid.
*/
public function isValidUsername($username = null)
{
@ -211,13 +213,15 @@ class Validator extends Regex
return false;
}
$extracted = $this->extractor->extractMentionedScreennames($username);
return count($extracted) === 1 && $extracted[0] === substr($username, 1);
}
/**
* Check whether a username is valid.
*
* @return boolean Whether the username is valid.
* @return bool Whether the username is valid.
*
* @deprecated since version 1.1.0
*/
public function validateUsername()
@ -229,7 +233,8 @@ class Validator extends Regex
* Check whether a list is valid.
*
* @param string $list The list name to validate.
* @return boolean Whether the list is valid.
*
* @return bool Whether the list is valid.
*/
public function isValidList($list = null)
{
@ -242,13 +247,15 @@ class Validator extends Regex
}
preg_match(self::$patterns['valid_mentions_or_lists'], $list, $matches);
$matches = array_pad($matches, 5, '');
return isset($matches) && $matches[1] === '' && $matches[4] && !empty($matches[4]) && $matches[5] === '';
}
/**
* Check whether a list is valid.
*
* @return boolean Whether the list is valid.
* @return bool Whether the list is valid.
*
* @deprecated since version 1.1.0
*/
public function validateList()
@ -260,7 +267,8 @@ class Validator extends Regex
* Check whether a hashtag is valid.
*
* @param string $hashtag The hashtag to validate.
* @return boolean Whether the hashtag is valid.
*
* @return bool Whether the hashtag is valid.
*/
public function isValidHashtag($hashtag = null)
{
@ -272,13 +280,15 @@ class Validator extends Regex
return false;
}
$extracted = $this->extractor->extractHashtags($hashtag);
return count($extracted) === 1 && $extracted[0] === substr($hashtag, 1);
}
/**
* Check whether a hashtag is valid.
*
* @return boolean Whether the hashtag is valid.
* @return bool Whether the hashtag is valid.
*
* @deprecated since version 1.1.0
*/
public function validateHashtag()
@ -290,10 +300,10 @@ class Validator extends Regex
* Check whether a URL is valid.
*
* @param string $url The url to validate.
* @param boolean $unicode_domains Consider the domain to be unicode.
* @param boolean $require_protocol Require a protocol for valid domain?
* @param bool $unicode_domains Consider the domain to be unicode.
* @param bool $require_protocol Require a protocol for valid domain?
*
* @return boolean Whether the URL is valid.
* @return bool Whether the URL is valid.
*/
public function isValidURL($url = null, $unicode_domains = true, $require_protocol = true)
{
@ -310,25 +320,27 @@ class Validator extends Regex
return false;
}
list($scheme, $authority, $path, $query, $fragment) = array_pad($matches, 5, '');
# Check scheme, path, query, fragment:
// Check scheme, path, query, fragment:
if (($require_protocol && !(
self::isValidMatch($scheme, self::$patterns['validate_url_scheme']) && preg_match('/^https?$/i', $scheme))
) || !self::isValidMatch($path, self::$patterns['validate_url_path']) || !self::isValidMatch($query, self::$patterns['validate_url_query'], true)
|| !self::isValidMatch($fragment, self::$patterns['validate_url_fragment'], true)) {
return false;
}
# Check authority:
// Check authority:
$authority_pattern = $unicode_domains ? 'validate_url_unicode_authority' : 'validate_url_authority';
return self::isValidMatch($authority, self::$patterns[$authority_pattern]);
}
/**
* Check whether a URL is valid.
*
* @param boolean $unicode_domains Consider the domain to be unicode.
* @param boolean $require_protocol Require a protocol for valid domain?
* @param bool $unicode_domains Consider the domain to be unicode.
* @param bool $require_protocol Require a protocol for valid domain?
*
* @return bool Whether the URL is valid.
*
* @return boolean Whether the URL is valid.
* @deprecated since version 1.1.0
*/
public function validateURL($unicode_domains = true, $require_protocol = true)
@ -340,6 +352,7 @@ class Validator extends Regex
* Determines the length of a tweet. Takes shortening of URLs into account.
*
* @param string $tweet The tweet to validate.
*
* @return int the length of a tweet.
*/
public function getTweetLength($tweet = null)
@ -353,6 +366,7 @@ class Validator extends Regex
$length += $x['indices'][0] - $x['indices'][1];
$length += stripos($x['url'], 'https://') === 0 ? $this->short_url_length_https : $this->short_url_length;
}
return $length;
}
@ -360,6 +374,7 @@ class Validator extends Regex
* Determines the length of a tweet. Takes shortening of URLs into account.
*
* @return int the length of a tweet.
*
* @deprecated since version 1.1.0
*/
public function getLength()
@ -372,15 +387,15 @@ class Validator extends Regex
*
* @param string $string The subject string to test.
* @param string $pattern The pattern to match against.
* @param boolean $optional Whether a match is compulsory or not.
* @param bool $optional Whether a match is compulsory or not.
*
* @return boolean Whether an exact match was found.
* @return bool Whether an exact match was found.
*/
protected static function isValidMatch($string, $pattern, $optional = false)
{
$found = preg_match($pattern, $string, $matches);
if (!$optional) {
return (($string || $string === '') && $found && $matches[0] === $string);
return ($string || $string === '') && $found && $matches[0] === $string;
} else {
return !(($string || $string === '') && (!$found || $matches[0] !== $string));
}

View file

@ -2,19 +2,18 @@
namespace App\Util\Media;
use Storage;
use App\Media;
use Image as Intervention;
use Storage;
class Image {
class Image
{
public $square;
public $landscape;
public $portrait;
public $thumbnail;
public $orientation;
public function __construct()
{
ini_set('memory_limit', config('pixelfed.memory_limit', '1024M'));
@ -24,7 +23,7 @@ class Image {
$this->portrait = $this->orientations()['portrait'];
$this->thumbnail = [
'width' => 293,
'height' => 293
'height' => 293,
];
$this->orientation = null;
}
@ -34,28 +33,28 @@ class Image {
return [
'square' => [
'width' => 1080,
'height' => 1080
'height' => 1080,
],
'landscape' => [
'width' => 1920,
'height' => 1080
'height' => 1080,
],
'portrait' => [
'width' => 1080,
'height' => 1350
]
'height' => 1350,
],
];
}
public function getAspectRatio($mediaPath, $thumbnail = false)
{
if(!is_file($mediaPath)) {
if (!is_file($mediaPath)) {
throw new \Exception('Invalid Media Path');
}
if($thumbnail) {
if ($thumbnail) {
return [
'dimensions' => $this->thumbnail,
'orientation' => 'thumbnail'
'orientation' => 'thumbnail',
];
}
@ -64,26 +63,25 @@ class Image {
$orientation = $aspect === 1 ? 'square' :
($aspect > 1 ? 'landscape' : 'portrait');
$this->orientation = $orientation;
return [
'dimensions' => $this->orientations()[$orientation],
'orientation' => $orientation
'orientation' => $orientation,
];
}
public function resizeImage(Media $media)
{
$basePath = storage_path('app/' . $media->media_path);
$basePath = storage_path('app/'.$media->media_path);
$this->handleResizeImage($media);
return;
}
public function resizeThumbnail(Media $media)
{
$basePath = storage_path('app/' . $media->media_path);
$basePath = storage_path('app/'.$media->media_path);
$this->handleThumbnailImage($media);
return;
}
public function handleResizeImage(Media $media)
@ -103,8 +101,7 @@ class Image {
$ratio = $this->getAspectRatio($file, $thumbnail);
$aspect = $ratio['dimensions'];
$orientation = $ratio['orientation'];
if($media->mime === 'image/gif' && !$thumbnail)
{
if ($media->mime === 'image/gif' && !$thumbnail) {
return;
}
@ -119,11 +116,11 @@ class Image {
$quality = config('pixelfed.image_quality');
$img->save($newPath, $quality);
if(!$thumbnail) {
if (!$thumbnail) {
$media->orientation = $orientation;
}
if($thumbnail == true) {
if ($thumbnail == true) {
$media->thumbnail_path = $converted['path'];
$media->thumbnail_url = url(Storage::url($converted['path']));
} else {
@ -132,21 +129,18 @@ class Image {
}
$media->save();
} catch (Exception $e) {
}
}
public function setBaseName($basePath, $thumbnail = false, $extension)
public function setBaseName($basePath, $thumbnail, $extension)
{
$png = false;
$path = explode('.', $basePath);
$name = ($thumbnail == true) ? $path[0] . '_thumb' : $path[0];
$name = ($thumbnail == true) ? $path[0].'_thumb' : $path[0];
$ext = last($path);
$basePath = "{$name}.{$ext}";
return ['path' => $basePath, 'png' => $png];
}
}

View file

@ -2,11 +2,8 @@
namespace App\Util\Webfinger;
use App\User;
use App\Util\Lexer\Nickname;
class Webfinger {
class Webfinger
{
public $user;
public $subject;
public $aliases;
@ -16,8 +13,8 @@ class Webfinger {
{
$this->user = $user;
$this->subject = '';
$this->aliases = array();
$this->links = array();
$this->aliases = [];
$this->links = [];
}
public function setSubject()
@ -26,6 +23,7 @@ class Webfinger {
$username = $this->user->username;
$this->subject = 'acct:'.$username.'@'.$host;
return $this;
}
@ -33,8 +31,9 @@ class Webfinger {
{
$this->aliases = [
$this->user->url(),
$this->user->permalink()
$this->user->permalink(),
];
return $this;
}
@ -46,19 +45,20 @@ class Webfinger {
[
'rel' => 'http://webfinger.net/rel/profile-page',
'type' => 'text/html',
'href' => $user->url()
'href' => $user->url(),
],
[
'rel' => 'http://schemas.google.com/g/2010#updates-from',
'type' => 'application/atom+xml',
'href' => $user->permalink('.atom')
'href' => $user->permalink('.atom'),
],
[
'rel' => 'self',
'type' => 'application/activity+json',
'href' => $user->permalink()
]
'href' => $user->permalink(),
],
];
return $this;
}
@ -71,10 +71,7 @@ class Webfinger {
return [
'subject' => $this->subject,
'aliases' => $this->aliases,
'links' => $this->links
'links' => $this->links,
];
}
}

View file

@ -2,18 +2,17 @@
namespace App\Util\Webfinger;
use App\User;
use App\Util\Lexer\Nickname;
class WebfingerUrl {
class WebfingerUrl
{
public static function generateWebfingerUrl($url)
{
$url = Nickname::normalizeProfileUrl($url);
$domain = $url['domain'];
$username = $url['username'];
$path = "https://{$domain}/.well-known/webfinger?resource={$username}@{$domain}";
return $path;
}
}

View file

@ -36,7 +36,7 @@ return [
'driver' => 'file', // redis, file, pdo, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '' // Instance of StorageInterface for custom driver
'provider' => '', // Instance of StorageInterface for custom driver
],
/*
@ -148,19 +148,19 @@ return [
'hints' => true, // Show hints for common mistakes
],
'mail' => [
'full_log' => false
'full_log' => false,
],
'views' => [
'data' => false, //Note: Can slow down the application, because the data can be quite large..
],
'route' => [
'label' => true // show complete route on bar
'label' => true, // show complete route on bar
],
'logs' => [
'file' => null
'file' => null,
],
'cache' => [
'values' => true // collect cache values
'values' => true, // collect cache values
],
],

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