w0bm.com v1.5z FULL.RETARD.BUILD.BUT.STILL.WORKS

This commit is contained in:
noxy
2019-08-26 16:58:26 +00:00
commit da71b95aa2
517 changed files with 143236 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Video;
use App\Models\User;
use App\Models\Category;
class AddTags extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tags';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Adds category names as tags and changes filters from users.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// Videos
echo 'UPDATING VIDEOS', PHP_EOL, '===============', PHP_EOL;
$count = 0;
Video::withTrashed()->with('category')->chunk(200, function($videos) use ($count) {
foreach($videos as $v) {
echo 'Updating Video with ID: ', $v->id, PHP_EOL;
$v->detag();
// quick and dirty. not 100% correct though.
if($v->category->shortname === 'pr0n')
$v->tag('nsfw');
else
$v->tag('sfw');
$v->tag(array_filter([$v->category->shortname
, $v->category->name
, $v->interpret
, $v->songtitle
, $v->imgsource
], function($elem) {
return !empty(trim($elem));
}));
$count++;
}
});
echo PHP_EOL, PHP_EOL, 'Updated ', $count, ' Videos.', PHP_EOL, PHP_EOL, PHP_EOL;
// User filters
echo 'UPDATING USERS', PHP_EOL, '==============', PHP_EOL;
$count = 0;
$categories = Category::withTrashed()->get()->keyBy('id');
User::withTrashed()->chunk(200, function($users) use (&$count, $categories) {
foreach($users as $u) {
echo 'Updating User: ', $u->username, PHP_EOL;
$u->categories = array_values($categories->filter(function($cat) use($u) {
return !in_array($cat->id, $u->categories);
})->map(function($cat) {
return $cat->shortname;
})->all());
$u->save();
$count++;
}
});
echo PHP_EOL, PHP_EOL, 'Updated ', $count, ' Users.', PHP_EOL, PHP_EOL, PHP_EOL;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Foundation\Inspiring;
class Inspire extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'inspire';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Display an inspiring quote';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->comment(PHP_EOL.Inspiring::quote().PHP_EOL);
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ReadException extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'exception {file=php://stdin}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Decrypts encrypted exception messages';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$input = $this->argument('file');
$c = file_get_contents($input);
if (false === $c) {
$this->error('File not found');
return;
}
//dd(explode(PHP_EOL, $c));
list($iv, $c) = explode(PHP_EOL, $c);
$iv = hex2bin($iv);
$m = openssl_decrypt($c, 'aes128', env('APP_KEY'), 0, $iv);
$this->line($m);
}
}

32
app/Console/Kernel.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Commands\AddTags::class,
Commands\Inspire::class,
Commands\ReadException::class,
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')
->hourly();
}
}

8
app/Events/Event.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
namespace App\Events;
abstract class Event
{
//
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
HttpException::class,
ModelNotFoundException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e)
{
if (app()->bound('sentry') && $this->shouldReport($e)) {
app('sentry')->captureException($e);
}
return parent::report($e);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
* @todo Perhaps replace odd encrypted error with Sentry notification
*/
public function render($request, Exception $e)
{
if ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
}
if ($this->isUnauthorizedException($e)) {
$e = new HttpException(403, $e->getMessage());
}
if ($this->isHttpException($e)) {
return $this->toIlluminateResponse($this->renderHttpException($e), $e);
} else {
$res = \Response::make(
view('errors.500', ['exception' => $e]),
500);
$res->exception = $e;
return $res;
}
//return parent::render($request, $e);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Helpers;
class HumanReadable
{
public static function bytesToHuman($bytes)
{
$units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'];
for ($i = 0; $bytes > 1024; $i++) {
$bytes /= 1024;
}
return round($bytes, 2) . ' ' . $units[$i];
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Video;
use App\Models\Banner;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Relations\HasMany;
use App\Http\Requests;
class CategoryController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Response
*/
public function index()
{
return view('categories', ['categories' => Category::all()]);
}
/**
* Show the form for creating a new resource.
*
* @return \Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return \Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param string $shortname
* @param int $id
* @return \Response
*/
public function showVideo($shortname, $id = null)
{
$category = Category::whereShortname($shortname)->first();
if (is_null($category)) {
return redirect()->back()->with('error', 'Category not found');
}
if (is_null($id)) {
$video = Video::getRandom($category);
if ($video instanceof HasMany) {
$video = $video->first();
}
else {
return redirect()->back()->with('error', 'Category is empty.');
}
return redirect($shortname . '/' . $video->id);
} else {
// Don't filter on specific video.
// TODO: Add warning page
$video = $category->videos()->find($id);
}
if (is_null($video)) {
return redirect()->back()->with('error', 'Category is empty.');
}
return view('video', [
'video' => $video,
'related' => $category,
'banner' => Banner::getRandom($video->isSfw())]);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param Request $request
* @param int $id
* @return \Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Response
*/
public function destroy($id)
{
//
}
}

View File

@@ -0,0 +1,237 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Models\Category;
use App\Models\Comment;
use App\Models\Message;
use App\Models\ModeratorLog;
use App\Models\Video;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class CommentController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
if(!$request->has('username')) return JsonResponse::create('Not found', '304');
$user = User::whereUsername(urldecode($request->get('username')))->first();
if(!$user) return JsonResponse::create('Not found', '304');
return $user->comments()->orderBy('id', 'desc')->paginate(10);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request, $id)
{
$user = auth()->check() ? auth()->user() : null;
$xhr = $request->ajax();
if(is_null($user)) return $xhr ? "Not logged in" : redirect()->back()->with('error', 'Not logged in');
if(!$request->has('comment')) return $xhr ? "You need to enter a comment" : redirect()->back()->with('error', 'You need to enter a comment');
if(mb_strlen(trim($request->get('comment'))) > 2000 ) return $xhr ? "Comment to long" : redirect()->back()->with('error', 'Comment to long');
$video = Video::findOrFail($id);
$com = new Comment();
$com->content = trim($request->get('comment'));
$com->user()->associate($user);
$com->video()->associate($video);
$com->save();
$sent = [];
foreach($com->getMentioned() as $mentioned) {
Message::send($user->id, $mentioned->id, $user->username . ' mentioned you in a comment', view('messages.commentmention', ['video' => $video, 'user' => $user, 'comment' => $com]));
$sent[] = $mentioned;
}
foreach($com->answered() as $answered) {
if(array_search($answered, $sent) !== false)
continue;
Message::send($user->id, $answered->id, $user->username . ' answered on your comment', view('messages.commentanswer', ['video' => $video, 'user' => $user, 'comment' => $com]));
$sent[] = $answered;
}
if($user->id != $video->user->id)
if(array_search($video->user, $sent) === false)
Message::send($user->id, $video->user->id, $user->username . ' commented on your video', view('messages.videocomment', ['video' => $video, 'user' => $user, 'comment' => $com]));
return $xhr ? view('partials.comment', ['comment' => $com, 'mod' => $user->can('delete_comment')]) : redirect()->back()->with('success', 'Comment successfully saved');
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$comment = Comment::whereId($id)->first();
if(!is_null($comment)) {
return JsonResponse::create(array(
'error' => 'null',
'comment' => Comment::whereId($id)->first()->content)
);
}
return JsonResponse::create(array(
'error' => 'comment_not_found'
));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
if(!($request->has('comment')))
return JsonResponse::create(array('error' => 'invalid_request'));
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return JsonResponse::create(array('error' => 'not_logged_in'));
if(!$user->can('edit_comment'))
return JsonResponse::create(array('error' => 'insufficient_permissions'));
if(is_null($comment = Comment::whereId($id)->first()))
return JsonResponse::create(array('error' => 'comment_not_found'));
$comment->content = trim($request->get('comment'));
$comment->save();
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'edit';
$log->target_type = 'comment';
$log->target_id = $id;
$log->save();
return JsonResponse::create(array(
'error' => 'null',
'rendered_comment' => Comment::simplemd($comment->content)
));
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request, $id)
{
if(!$request->has('reason'))
return 'invalid_request';
$reason = trim($request->get('reason'));
if($reason == '')
return 'invalid_request';
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return 'not_logged_in';
if(!$user->can('delete_comment'))
return 'insufficient_permissions';
$comment = Comment::whereId($id)->first();
if(is_null($comment))
return 'comment_not_found';
$receiver = $comment->user;
$video = $comment->video;
Comment::destroy($id);
if($user->id != $receiver->id)
Message::send(1, $receiver->id, 'A moderator deleted your comment', view('messages.moderation.commentdelete', ['video' => $video, 'comment' => $comment, 'reason' => $reason]));
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'delete';
$log->target_type = 'comment';
$log->target_id = $id;
$log->reason = $reason;
$log->save();
return 'success';
}
public function restore(Request $request, $id)
{
if(!$request->has('reason'))
return 'invalid_request';
$reason = trim($request->get('reason'));
if($reason == '')
return 'invalid_request';
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return 'not_logged_in';
if(!$user->can('delete_comment'))
return 'insufficient_permissions';
$comment = Comment::withTrashed()->whereId($id)->first();
if(is_null($comment))
return 'comment_not_found';
if(!$comment->trashed())
return 'comment_not_deleted';
$receiver = $comment->user;
$video = $comment->video;
$comment->restore();
if($user->id != $receiver->id)
Message::send(1, $receiver->id, 'A moderator restored your comment', view('messages.moderation.commentrestore', ['video' => $video, 'comment' => $comment, 'reason' => $reason]));
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'restore';
$log->target_type = 'comment';
$log->target_id = $id;
$log->reason = $reason;
$log->save();
return 'success';
}
}

View File

@@ -0,0 +1,13 @@
<?php
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;
abstract class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

View File

@@ -0,0 +1,112 @@
<?php
namespace App\Http\Controllers;
use App\Models\Message;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Http\Requests;
use Illuminate\Http\Response;
class MessageController extends Controller
{
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
if(!auth()->check()) return JsonResponse::create('Not found', '304');
return auth()->user()->messagesRecv()->orderBy('id', 'desc')->paginate(15);
}
public function page()
{
if(!auth()->check()) return redirect()->back()->with('warning', 'You are not logged in');
return view('messages');
}
public function read(Request $request)
{
if(!auth()->check()) return Response::create('Unauthorized', '401');
if($request->has('m_ids')) {
$ids = $request->get('m_ids');
Message::whereTo(auth()->user()->id)->whereIn('id', $ids)->update(['read' => \Carbon\Carbon::now()]);
return 1;
}
}
public function readall()
{
if(!auth()->check()) return Response::create('Unauthorized', '401');
Message::whereTo(auth()->user()->id)->unread()->update(['read' => \Carbon\Carbon::now()]);
return 1;
}
/**
* Show the form for creating a new resource.
*
* @return Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return Response
*/
public function destroy($id)
{
//
}
}

View File

@@ -0,0 +1,306 @@
<?php
namespace App\Http\Controllers;
use App\Models\Report;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class ReportController extends Controller
{
private $fromMail = "otter@w0bm.com";
private $fromName = "w0bm";
private $toMail = "admin@w0bm.com";
private $toName = "w0bm";
private $subject = "webm reported";
private $baseURL = "http://w0bm.com/";
/**
* Made by klee
* Testing to make report crap
*
*/
public function report(Request $request)
{
if(is_array($request->input('reportReasons'))) {
$reportReasons = "<li>".implode("</li><li>", $request->input('reportReasons'));
} else {
$reportReasons = "<li>".$request->input('reportReasons')."</li>";
}
if($request->user()->username == "" || $request->user()->username == null) {
$username = "User is <b>anonymous</b> because he is not registered";
} else {
$username = $request->user()->username;
}
$data = array(
"videoURL" => $this->baseURL.$request->route('id'),
"reportReasons" => $reportReasons,
"reportText" => htmlspecialchars($request->input('reportText')),
"username" => $username,
"videoID" => $request->route('id'),
"message" => array(
"html" => 'html message',
"text" => 'text message',
"to" => array(
array("name" => 'admin@w0bm.com', "email" => 'admin@w0bm.com')
),
"from_email" => 'otter@w0bm.com',
"from_name" => 'from w0bm',
"subject" => 'the subject',
"track_opens" => true,
"track_clicks" => true
),
"async" => false,
"debugOutput" => print_r(get_class_methods($request), true).print_r($request->route()->parameters(), true)
);
//$postString = json_encode($data);
\Mail::send('emails.report', $data, function ($msg) {
$msg->from($this->fromMail, $this->fromName);
$msg->to($this->toMail, $this->toName);
$msg->subject($this->subject);
});
return redirect()->back()->with('success', 'Report successfully sent');;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
/*
if(!$request->has('username')) return JsonResponse::create('Not found', '304');
$user = User::whereUsername(urldecode($request->get('username')))->first();
if(!$user) return JsonResponse::create('Not found', '304');
return $user->comments()->orderBy('id', 'desc')->paginate(10);
*/
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request, $id)
{
/*
$user = auth()->check() ? auth()->user() : null;
$xhr = $request->ajax();
if(is_null($user)) return $xhr ? "Not logged in" : redirect()->back()->with('error', 'Not logged in');
if(!$request->has('comment')) return $xhr ? "You need to enter a comment" : redirect()->back()->with('error', 'You need to enter a comment');
if(mb_strlen(trim($request->get('comment'))) > 2000 ) return $xhr ? "Comment to long" : redirect()->back()->with('error', 'Comment to long');
$video = Video::findOrFail($id);
$com = new Comment();
$com->content = trim($request->get('comment'));
$com->user()->associate($user);
$com->video()->associate($video);
$com->save();
$sent = [];
foreach($com->getMentioned() as $mentioned) {
Message::send($user->id, $mentioned->id, $user->username . ' mentioned you in a comment', view('messages.commentmention', ['video' => $video, 'user' => $user, 'comment' => $com]));
$sent[] = $mentioned;
}
foreach($com->answered() as $answered) {
if(array_search($answered, $sent) !== false)
continue;
Message::send($user->id, $answered->id, $user->username . ' answered on your comment', view('messages.commentanswer', ['video' => $video, 'user' => $user, 'comment' => $com]));
$sent[] = $answered;
}
if($user->id != $video->user->id)
if(array_search($video->user, $sent) === false)
Message::send($user->id, $video->user->id, $user->username . ' commented on your video', view('messages.videocomment', ['video' => $video, 'user' => $user, 'comment' => $com]));
return $xhr ? view('partials.comment', ['comment' => $com, 'mod' => $user->can('delete_comment')]) : redirect()->back()->with('success', 'Comment successfully saved');
*/
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
/*
$comment = Comment::whereId($id)->first();
if(!is_null($comment)) {
return JsonResponse::create(array(
'error' => 'null',
'comment' => Comment::whereId($id)->first()->content)
);
}
return JsonResponse::create(array(
'error' => 'comment_not_found'
));
*/
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
/*
if(!($request->has('comment')))
return JsonResponse::create(array('error' => 'invalid_request'));
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return JsonResponse::create(array('error' => 'not_logged_in'));
if(!$user->can('edit_comment'))
return JsonResponse::create(array('error' => 'insufficient_permissions'));
if(is_null($comment = Comment::whereId($id)->first()))
return JsonResponse::create(array('error' => 'comment_not_found'));
$comment->content = trim($request->get('comment'));
$comment->save();
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'edit';
$log->target_type = 'comment';
$log->target_id = $id;
$log->save();
*/
return JsonResponse::create(array(
'error' => 'null',
'rendered_comment' => "test rendered comment"//Comment::simplemd($comment->content)
));
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request, $id)
{
/*
if(!$request->has('reason'))
return 'invalid_request';
$reason = trim($request->get('reason'));
if($reason == '')
return 'invalid_request';
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return 'not_logged_in';
if(!$user->can('delete_comment'))
return 'insufficient_permissions';
$comment = Comment::whereId($id)->first();
if(is_null($comment))
return 'comment_not_found';
$receiver = $comment->user;
$video = $comment->video;
Comment::destroy($id);
if($user->id != $receiver->id)
Message::send(1, $receiver->id, 'A moderator deleted your comment', view('messages.moderation.commentdelete', ['video' => $video, 'comment' => $comment, 'reason' => $reason]));
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'delete';
$log->target_type = 'comment';
$log->target_id = $id;
$log->reason = $reason;
$log->save();
*/
return 'success';
}
public function restore(Request $request, $id)
{
/*
if(!$request->has('reason'))
return 'invalid_request';
$reason = trim($request->get('reason'));
if($reason == '')
return 'invalid_request';
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return 'not_logged_in';
if(!$user->can('delete_comment'))
return 'insufficient_permissions';
$comment = Comment::withTrashed()->whereId($id)->first();
if(is_null($comment))
return 'comment_not_found';
if(!$comment->trashed())
return 'comment_not_deleted';
$receiver = $comment->user;
$video = $comment->video;
$comment->restore();
if($user->id != $receiver->id)
Message::send(1, $receiver->id, 'A moderator restored your comment', view('messages.moderation.commentrestore', ['video' => $video, 'comment' => $comment, 'reason' => $reason]));
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'restore';
$log->target_type = 'comment';
$log->target_id = $id;
$log->reason = $reason;
$log->save();
*/
return 'success';
}
}

View File

@@ -0,0 +1,401 @@
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\User;
use App\Models\UserFavorite;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Models\ModeratorLog;
use App\Models\Banner;
use Symfony\Component\HttpFoundation\Response;
use Toddish\Verify\Helpers\Verify;
class UserController extends Controller
{
/**
* @param Request $request
* @return \Response
*/
public function login(Request $request)
{
if($request->has('identifier') && $request->has('password')) {
switch(\Auth::verify([
'identifier' => $request->get('identifier'),
'password' => $request->get('password')
], $request->has('remember')))
{
case Verify::SUCCESS:
#\Session::put('background', auth()->user()->background);
return redirect("/")->with('success', 'Login successful');
case Verify::INVALID_CREDENTIALS:
return redirect()->back()->with('error', 'Invalid credentials');
case Verify::DISABLED:
$user = User::whereUsername($request->get('identifier'))
->orWhere('email', $request->get('identifier'))
->first();
if($user->banend->eq(Carbon::createFromTimestampUTC(1))) {
return view('banned', ['user' => $user, 'perm' => true]);
}
// if ban expired unban and relogin.
if($user->banend->lt(Carbon::now())) {
$user->banend = null;
$user->disabled = 0;
$user->banreason = null;
$user->save();
return $this->login($request);
}
return view('banned', ['user' => $user, 'perm' => false]);
case Verify::UNVERIFIED:
return redirect()->back()->with('error', 'Please verify your account');
}
}
return redirect()->back()->with('error', 'Missing credentials');
}
public function logout()
{
if(!auth()->check()) return redirect()->back()->with('warning', 'You are not logged in');
auth()->logout();
return redirect('/')->with('success', 'Logout successful');
}
/**
* Display a listing of the resource.
*
* @return \Response
*/
public function index()
{
//
}
/**
* Add tags to filter
*
* @param Request $request
* @return Response
*/
public function filter(Request $request) {
//dd($request->get('categories'));
if(!auth()->check())
return Response::create("Not logged in", 401);
if(!$request->has('filter'))
$filter = [];
else
$filter = explode(',', $request->get('filter'));
auth()->user()->categories = $filter;
auth()->user()->save();
if(!$request->ajax())
return redirect()->back()->with('success', 'Filter settings saved');
return Response::create(json_encode($filter));
}
/**
* Show the form for creating a new resource.
*
* @return \Response
*/
public function create()
{
if(auth()->check()) {
\Session::reflash();
\Session::flash('info', 'Cannot register when logged in');
return redirect('/');
}
return view('register');
}
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return \Response
*/
public function store(Request $request)
{
if(auth()->check()) return redirect()->back()->with('info', 'Cannot register when logged in');
$validator = \Validator::make($request->all(), [
'username' => 'required|unique:users|min:3|max:25|alpha_num',
//'email' => 'required|email|unique:users|confirmed',
'password' => 'required|min:6|confirmed',
'g-recaptcha-response' => 'required|recaptcha'
]);
if($validator->fails()) {
return redirect()->back()->withErrors($validator->errors())
->withInput($request->except(['password', 'password_confirmation']));
}
//$activation_token = str_random(8) . md5($request->get('email')) . str_random(10);
$user = new User();
$user->username = $request->get('username');
$user->email = ""; //$request->get('email');
$user->password = $request->get('password');
$user->activation_token = ""; //$activation_token;
$user->disabled = 0;
$user->verified = 1;
$user->categories = [];
if($user->save()) {
/*$data = [
'username' => $user->username,
'activation_token' => $activation_token
];*/
// Send Mail
/*\Mail::queue('emails.activation', $data, function($message) use ($user) {
$message->to($user->email, $user->username)->subject('Welcome to w0bm. Activate your account');
});*/
return redirect('/')->with('info', 'Congratulations! You can now login!');
} else {
return redirect()->back()->with('error', 'Account could not be created')->withInput($request->except(['password', 'password_confirmation']));
}
}
public function activate($token)
{
$user = User::where('activation_token', '=', $token)->first();
if(!$user) {
return redirect('/')->with('error', 'Account already activate or no account found');
}
$user->verified = 1;
$user->activation_token = null;
$user->save();
auth()->login($user);
return redirect('/')->with('success', 'Successfully activate and logged in.');
}
/**
* Display the specified resource.
*
* @param string $username
* @return \Response
*/
public function show($username)
{
$user = User::where('username', '=', $username)->first();
if(!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
$vids = $user->videos()->filtered()->paginate(50);
return view('profile', ['title' => 'Uploads', 'user' => $user, 'videos' => $vids]);
}
public function show_favs($username)
{
$user = UserFavorite::where('username', '=', $username)->first();
if (!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
$vids = $user->favs()->filtered()->orderBy('favorites.created_at')->paginate(50);
return view('profile', ['title' => 'Favorites', 'user' => $user, 'videos' => $vids]);
}
public function show_comments($username)
{
$user = User::where('username', '=', $username)->first();
if(!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
return view('comments', ['user' => $user]);
}
public function ban(Request $request, $username)
{
if(!($request->has('reason') && $request->has('duration')))
return redirect()->back()->with('error', 'Invalid Request');
if(trim($reason = $request->get('reason')) == '')
return redirect()->back()->with('error', 'You need to specify a ban reason');
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return redirect()->back()->with('error', 'Not logged in');
if(!$user->can('edit_user'))
return redirect()->back()->with('error', 'Insufficient permissions');
$perm = false;
if(($duration = $request->get('duration')) == '-1') {
$duration = Carbon::createFromTimestampUTC(1);
$perm = true;
} else {
preg_match('/^(\d+[yYaA])?\s*(\d+M)?\s*(\d+[wW])?\s*(\d+[dD])?\s*(\d+[Hh])?\s*(\d+[m])?\s*(\d+[sS])?$/m', $duration, $duration);
array_shift($duration);
$duration = array_map(function($elem) {
return intval(mb_substr($elem, 0, -1));
}, $duration);
$duration = Carbon::now()
->addYears($duration[0] ?? 0)
->addMonths($duration[1] ?? 0)
->addWeeks($duration[2] ?? 0)
->addDays($duration[3] ?? 0)
->addHours($duration[4] ?? 0)
->addMinutes($duration[5] ?? 0)
->addSeconds($duration[6] ?? 0);
}
$userToBan = User::whereUsername($username)->first();
if(is_null($user))
return redirect()->back()->with('error', 'User not found');
$userToBan->disabled = 1;
$userToBan->banreason = $reason;
$userToBan->banend = $duration;
$userToBan->save();
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'ban';
$log->target_type = 'user';
$log->target_id = $userToBan->id;
$log->reason = $reason;
$log->save();
if($perm)
return redirect()->back()->with('success', 'User ' . $userToBan->username . ' has been permanently banned');
else
return redirect()->back()->with('success', 'User ' . $userToBan->username . ' has been banned until ' . $userToBan->banend->format('d.m.Y H:i:s') . ' UTC');
}
/**
* Show the form for editing the specified resource.
*
* @param string $username
* @return \Response
*/
public function edit($username)
{
//
}
/**
* Update the specified resource in storage.
*
* @param Request $request
* @param int $id
* @return \Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Response
*/
public function destroy($id)
{
//
}
public function random($username) {
$user = User::where('username', '=', $username)->first();
if (!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
$id = $user->videos()->filtered()->countScoped()->count() - 1;
if ($id < 0) {
return redirect()->back()->with('error', 'User has no uploads (Check your filter settings)');
}
$id = mt_rand(0, $id);
$vid = $user->videos()->filtered()->skip($id)->first()->id;
return redirect('/user/' . $username . '/uploads/' . $vid);
}
public function play($username, $id) {
$user = User::where('username', '=', $username)->first();
if (!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
$vid = $user->videos()->filtered()->find($id);
if (!$vid) {
return redirect()->back()->with('error', 'Video not found on user');
}
return view('video', [
'video' => $vid,
'related' => $user,
'banner' => Banner::getRandom($vid->isSfw())
]);
}
// TODO: Cleanup. less Repetion between random and random_vav/play and play_fav
// Only difference are the redirect urls and the Base Model
public function random_fav($username) {
$user = UserFavorite::where('username', '=', $username)->first();
if (!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
$id = $user->videos()->filtered()->countScoped()->count() - 1;
if ($id < 0) {
return redirect()->back()->with('error', 'No favorites (Check your filter settings)');
}
$id = mt_rand(0, $id);
$vid = $user->videos()->filtered()->skip($id)->first()->id;
return redirect('/user/' . $username . '/favs/' . $vid);
}
public function play_fav($username, $id) {
$user = UserFavorite::where('username', '=', $username)->first();
if (!$user) {
return redirect()->back()->with('error', 'Unknown username');
}
$vid = $user->videos()->filtered()->find($id);
if (!$vid) {
return redirect()->back()->with('error', 'Video not found on user');
}
return view('video', [
'video' => $vid,
'related' => $user,
'banner' => Banner::getRandom($vid->isSfw())
]);
}
public function setLayout(Request $request) {
if(!auth()->check())
return Response::create("unauthorized", 401);
if(!$request->has('layout'))
return Response::create("bad request", 400);
$layout = $request->get('layout');
if($layout !== strval(intval($layout)))
return Response::create("bad request", 400);
if(!in_array("layout" . $layout, array_map(function ($v) { return basename($v); }, glob("../resources/views/layout*"))))
return Response::create("bad request", 400);
auth()->user()->layout = $request->get('layout');
auth()->user()->save();
return Response::create("success", 200);
}
}

View File

@@ -0,0 +1,331 @@
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Comment;
use App\Models\Message;
use App\Models\ModeratorLog;
use App\Models\Video;
use App\Models\Banner;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class VideoController extends Controller
{
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index(Request $request) {
if($request->has('q')){
$needle = trim($request->input('q'));
return view('index', [
'videos' => Video::filtered()->withAnyTagsFuzzy($needle)
->orderBy('id', 'asc')
->paginate(20)->appends(['q' => $needle]),
'categories' => Category::all(),
'q' => $needle
]);
}
return view('index', [
'videos' => Video::filtered()->orderBy('id', 'ASC')->paginate(20),
'categories' => Category::all()
]);
}
/**
* Show the form for creating a new resource.
*
* @return Response
*/
public function create()
{
$user = auth()->check() ? auth()->user() : null;
return view('upload', ['user' => $user]);
}
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
/*var_dump($request->hasFile('file'));*/ if(!$request->hasFile('file') || !$request->has('category') || !$request->has('tags'))
return new JsonResponse(['error' => 'invalid_request']);
$tags = $request->get('tags');
if(mb_strpos($tags, 'sfw') === false && mb_strpos($tags, 'nsfw') === false)
return new JsonResponse(['error' => 'invalid_request']);
$user = auth()->check() ? auth()->user() : null;
if(is_null($user))
return new JsonResponse(['error' => 'not_logged_in']);
if(!$user->can('break_upload_limit') && $user->videos()->newlyups()->count() >= 10)
return new JsonResponse(['error' => 'uploadlimit_reached']);
$file = $request->file('file');
if(!$file->isValid()
|| mb_strtolower($file->getClientOriginalExtension()) !== 'webm'
|| mb_strtolower($file->getMimeType()) !== 'video/webm')
return new JsonResponse(['error' => 'invalid_file']);
if(!$user->can('break_max_filesize') && $file->getSize() > 41943040)
return new JsonResponse(['error' => 'file_too_big']);
if(($v = Video::withTrashed()->where('hash', '=', sha1_file($file->getRealPath()))->first()) !== null) {
if($v->trashed())
return new JsonResponse(['error' => 'already_exists']);
return new JsonResponse([
'error' => 'already_exists',
'video_id' => $v->id
]);
}
// meh time()
$file = $file->move(public_path() . '/b/', 'w0bm_' . time() . '.webm');
$hash = sha1_file($file->getRealPath());
$video = new Video();
$video->file = basename($file->getRealPath());
if(!$video->checkFileEncoding()) {
unlink($file->getRealPath());
// return before $video->save() so no need to clean up db
return new JsonResponse(['error' => 'erroneous_file_encoding']);
}
$video->videotitle = $request->get('videotitle', null);
$video->interpret = $request->get('interpret', null);
$video->songtitle = $request->get('songtitle', null);
$video->imgsource = $request->get('imgsource', null);
$video->user()->associate($user);
$video->category()->associate(Category::findOrFail($request->get('category')));
$video->hash = $hash;
$video->save();
$video->tag($tags);
$video->tag($video->videotitle);
$video->tag($video->interpret);
$video->tag($video->songtitle);
$video->tag($video->imgsource);
$video->tag($video->category->shortname);
$video->tag($video->category->name);
// TODO: outsource to different process (async)
$video->createThumbnail();
// Discord
if (config('discord.enabled') && config('discord.webhookurl')) {
$nsfw = in_array('nsfw', $video->getTagArrayNormalizedAttribute());
$nsfw = $nsfw ? ' :exclamation: **NSFW** :exclamation:' : '';
$message = config('discord.message');
$message = str_replace(
['<USER>', '<ID>', '<NSFW>'],
[$user->username, $video->id, $nsfw],
$message
);
$url = config('discord.webhookurl');
$payload = json_encode([
'content' => $message,
]);
// exec with & so it is async
exec("curl -H \"Content-Type: application/json; charset=UTF-8\" -X POST -d '$payload' '$url' > /dev/null &");
}
return new JsonResponse([
'error' => 'null',
'video_id' => $video->id
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return Response
*/
public function show($id) {
// TODO: filter on direct id link??
$video = Video::with('tags')->find($id);
if(is_null($video))
return view('deleted');
#->back();
#->with('error', 'No video with that ID found');
$sfw = $video->tags->contains(function($key, $tag) {
return $tag->normalized === 'sfw';
});
return view('video', [
'video' => $video,
'banner' => Banner::getRandom($sfw)
]);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id) {
if(!auth()->check())
return response('Not logged in', 403);
$user = auth()->user();
if(!$request->ajax())
return response('Invalid request', 400);
$v = Video::findOrFail($id);
if(!$user->can('edit_video') && $user->id != $v->user_id)
return response('Not enough permissions', 403);
if($request->has('interpret')) {
$v->interpret = $request->input('interpret');
$v->tag($request->input('interpret'));
}
if($request->has('songtitle')) {
$v->songtitle = $request->input('songtitle');
$v->tag($request->input('songtitle'));
}
if($request->has('imgsource')) {
$v->imgsource = $request->input('imgsource');
$v->tag($request->input('imgsource'));
}
if($request->has('videotitle')) {
$v->videotitle = $request->input('videotitle');
$v->tag($request->input('videotitle'));
}
if($request->has('category')) {
$cat = Category::findOrFail($request->input('category'));
$v->category()->associate($cat);
$v->tag($cat->name);
$v->tag($cat->shortname);
}
$v->save();
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'edit';
$log->target_type = 'video';
$log->target_id = $v->id;
$log->save();
return $v;
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Response
*/
public function destroy(Request $request, $id)
{
$user = auth()->check() ? auth()->user() : null;
if(is_null($user)) return new JsonResponse(['error' => 'not_logged_in']);
if(!$request->has('reason') || trim($request->get('reason')) == '') return new JsonResponse(['error' => 'invalid_request']);
$reason = trim($request->get('reason'));
if($user->can('delete_video')) {
$warnings = [];
$vid = Video::find($id);
if(!$vid)
return new JsonResponse(['error' => 'video_not_found']);
foreach($vid->comments as $comment) {
$comment->delete(); // delete associated comments
}
$vid->faved()->detach();
if(!\File::move(public_path() . '/b/' . $vid->file, storage_path() . '/deleted/' . $vid->file))
$warnings[] = 'Could not move file';
$vid->delete();
$receiver = $vid->user;
if($user->id != $receiver->id)
Message::send(1, $receiver->id, 'A moderator deleted your video', view('messages.moderation.videodelete', ['video' => $vid, 'reason' => $reason, 'videoinfo' => ['artist' => $vid->interpret, 'songtitle' => $vid->songtitle, 'video_source' => $vid->imgsource, 'category' => $vid->category->name]]));
$log = new ModeratorLog();
$log->user()->associate($user);
$log->type = 'delete';
$log->target_type = 'video';
$log->target_id = $id;
$log->reason = $reason;
$log->save();
return new JsonResponse(['error' => 'null', 'warnings' => $warnings]);
}
return new JsonResponse(['error' => 'insufficient_permissions']);
}
public function favorite($id) {
$user = auth()->check() ? auth()->user() : null;
$xhr = \Request::ajax();
if(is_null($user)) return $xhr ? "Not logged in" : redirect()->back()->with('error', 'Not logged in');
if($user->hasFaved($id)) {
$user->favs()->detach($id);
return $xhr ? "Video removed from favorites" : redirect()->back()->with('success', 'Video removed from favorites');
} else {
$user->favs()->attach($id);
return $xhr ? "Video added to favorites" : redirect()->back()->with('success', 'Video added to favorites');
}
}
/**
* @param Request $request
* @return Video | Bool
*/
public function tag(Request $request, $id) {
if(!$request->has('tags')) return new JsonResponse(["error" => "invalid_request"]);
$tags = $request->get('tags');
if(!count($tags)) return new JsonResponse(["error" => "no_tags_specified"]);
$v = Video::findOrFail($id);
if(is_null($v)) return new JsonResponse(["error" => "video_not_found"]);
$v->tag($tags);
$v['error'] = 'null';
$v['can_edit_video'] = auth()->check() ? auth()->user()->can('edit_video') : false;
return $v;
}
public function untag(Request $request, $id) {
if(!$request->has('tag') || trim($request->get('tag')) == "") return new JsonResponse(["error" => "invalid_request"]);
$user = auth()->check() ? auth()->user() : null;
if(is_null($user)) return new JsonResponse(["error" => "not_logged_in"]);
if(!$user->can('edit_video')) return new JsonResponse(["error" => "insufficient_permissions"]);
$tag = trim($request->get('tag'));
$v = Video::findOrFail($id);
if(is_null($v)) return new JsonResponse(["error" => "video_not_found"]);
$v = $v->untag($tag);
$v['error'] = 'null';
return $v;
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

37
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware = [
\Clockwork\Support\Laravel\ClockworkMiddleware::class,
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
Middleware\VerifyCsrfToken::class,
Middleware\LogoutBanned::class,
Middleware\Jsonp::class
];
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => Middleware\RedirectIfAuthenticated::class,
'theme' => Middleware\Theme::class,
];
}

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/login');
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as BaseEncrypter;
class EncryptCookies extends BaseEncrypter
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\JsonResponse;
class Jsonp {
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
if ($response->headers->get('content-type') == 'application/json'
&& $request->has('callback'))
{
if (get_class($response) == JsonResponse::class) {
return $response->setCallback($request->input('callback'));
}
// TODO fix stripping headers
return response()->json($response->original)->setCallback($request->input('callback'));
}
return $response;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use Closure;
class LogoutBanned
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$user = auth()->user();
if($user && $user->isBanned()) {
auth()->logout();
return redirect()->back()->with('error', 'You are banned');
}
return $next($request);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class RedirectIfAuthenticated
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return redirect('/');
}
return $next($request);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\View\Factory;
class Theme
{
protected $auth;
protected $view;
public function __construct(Guard $auth, Factory $view)
{
$this->auth = $auth;
$this->view = $view;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$paths = $this->view->getFinder()->getPaths();
foreach ($paths as &$p) {
$p .= "/layout" . (auth()->check() ? auth()->user()->layout : 1);
}
$this->view->setFinder(new \Illuminate\View\FileViewFinder($this->view->getFinder()->getFilesystem(), $paths));
return $next($request);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'api/video/upload'
];
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
{
//
}

149
app/Http/routes.php Normal file
View File

@@ -0,0 +1,149 @@
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
Route::get('/', ['as' => 'home', function () {
Session::reflash();
// Dummy query to calculate rows
$video = \App\Models\Video::getRandom()->first();
return redirect($video->id);
}])->middleware('auth');
Route::post('filter', 'UserController@filter');
// /api
Route::group(['prefix' => 'api'], function() {
// /api/messages
Route::group(['prefix' => 'messages'], function() {
Route::get('', 'MessageController@index');
Route::post('read', 'MessageController@read');
Route::get('readall', 'MessageController@readall');
});
// /api/comments
Route::group(['prefix' => 'comments'], function() {
Route::get('/', 'CommentController@index');
Route::get('/{id}', 'CommentController@show')->where('id', '[0-9]+');
Route::post('{id}/edit', 'CommentController@update')->where('id', '[0-9]+');
Route::post('{id}/delete', 'CommentController@destroy')->where('id', '[0-9]+');
Route::post('{id}/restore', 'CommentController@restore')->where('id', '[0-9]+');
});
// /api/user
Route::group(['prefix' => 'user'], function() {
Route::post('{username}/ban', 'UserController@ban');
Route::get('/layout', 'UserController@setLayout');
});
// /api/video
Route::group(['prefix' => 'video'], function() {
Route::get('random', function() {
return \App\Models\Video::getRandom()->with(['category', 'user' => function($query) {
$query->addSelect('username', 'id');
}])->first();
});
Route::get('latest', function(\Illuminate\Http\Request $req) {
if ($req->has('filtered') && $req->get('filtered')) {
return \App\Models\Video::filtered()->orderBy('id', 'DESC')->first();
}
return \App\Models\Video::orderBy('id', 'DESC')->first();
});
Route::get('{id}', function($id) {
$res = \App\Models\Video::with(['category', 'user' => function($query) {
$query->addSelect('username', 'id');
}])->find($id);
if(!$res) {
return response(['message' => 'Video not found'], 404);
}
return $res;
})->where('id', '[0-9]+');
Route::post('{id}/delete', 'VideoController@destroy')->where('id', '[0-9]+');
Route::post('{id}/tag', 'VideoController@tag')->where('id', '[0-9]+');
Route::post('{id}/untag', 'VideoController@untag')->where('id', '[0-9]+');
Route::post('upload', 'VideoController@store')->middleware('auth.basic');
});
Route::post('upload', 'VideoController@store');
});
Route::group(["middleware" => "theme"], function() {
Route::post('report/{id}', 'ReportController@report'); // added by klee
Route::get('messages', 'MessageController@page');
Route::get('user/{username}', 'UserController@show')->middleware('auth');
Route::get('user/{username}/uploads', 'UserController@random')->middleware('auth');
Route::get('user/{username}/uploads/{id}', 'UserController@play')->where('id', '[0-9]+')->middleware('auth');
Route::get('user/{username}/favs', 'UserController@random_fav')->middleware('auth');
Route::get('user/{username}/favs/{id}', 'UserController@play_fav')->where('id', '[0-9]+')->middleware('auth');
Route::get('user/{username}/favs/index', 'UserController@show_favs')->middleware('auth');
Route::get('user/{username}/comments', 'UserController@show_comments')->middleware('auth');
Route::get('logout', 'UserController@logout');
Route::post('login', 'UserController@login');
Route::get('register', 'UserController@create');
Route::post('register', 'UserController@store');
Route::get('activate/{token}', 'UserController@activate');
Route::get('index', 'VideoController@index')->middleware('auth');
Route::post('index/{id}', 'VideoController@update')->middleware('auth');
Route::get('upload', 'VideoController@create')->middleware('auth');
Route::get('categories', 'CategoryController@index')->middleware('auth');
Route::get('webm', function() { return view('webm'); });
Route::get('about', function() { return view('about'); });
Route::get('irc', function() { return view('irc'); });
Route::get('rules', function() { return view('rules'); });
Route::get('contact', function() { return view('contact'); });
Route::get('privacy', function() { return view('privacy'); });
Route::get('teamspeak', function() { return view('teamspeak'); });
Route::get('news', function() { return view('news'); });
Route::get('0x40', function() { return view('0x40'); });
Route::get('stats', function() {
return view('stats', [
'user_count' => \App\Models\User::count(),
'upload_count' => \App\Models\Video::count(),
'comment_count' => \App\Models\Comment::count(),
//'fav_count' => \App\Models\UserFavorite::count(),
'latest_video' => \App\Models\Video::getLastId(),
'newest_user' => \App\Models\User::orderBy('id', 'DESC')->first()->username,
'dirsize' => shell_exec("(du -sh " . public_path() . "/b | cut -f1)")
]);
});
Route::get('/latest', function () {
Session::reflash();
$video = \App\Models\Video::orderBy('id', 'DESC')->first();
return redirect($video->id);
});
#Route::get('help', function() { return view('help'); });
#Route::get('announcement', function() { return view('announcement'); });
#Route::get('map', function() { return view('map'); });
#Route::get('donate', function() {
# return view('donate', [
# 'donations' => \App\Models\Donation::orderBy('timestamp', 'DESC')->get()
# ]);
#});
Route::get('transparency', function() { return view('transparency'); });
Route::get('login', function() { return view('login'); });
#Route::get('counter-strike', function() { return view('counter-strike'); });
Route::get('{id}', 'VideoController@show')->where('id', '[0-9]+');
Route::get('{id}/fav', 'VideoController@favorite')->where('id', '[0-9]+');
Route::post('{id}', 'CommentController@store')->where('id', '[0-9]+');
Route::get('{shortname}', 'CategoryController@showVideo')->where('shortname', '[a-z][a-z0-9]+')->middleware('auth');
Route::get('{shortname}/{id}', 'CategoryController@showVideo')->where(['shortname' => '[a-z][a-z0-9]+', 'id' => '[0-9]+'])->middleware('auth');
});

21
app/Jobs/Job.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
abstract class Job
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "onQueue" and "delay" queue helper methods.
|
*/
use Queueable;
}

0
app/Listeners/.gitkeep Normal file
View File

40
app/Models/Banner.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
// Maybe this will in a n to m relation with video someday
class Banner extends Model
{
protected $casts = [
'sfw' => 'boolean'
];
protected $dates = [
'created_at',
'updated_at',
'until'
];
// If this would be in relation with video the $sfw could be
// figured out dynamically
public static function getRandom($sfw = true) {
$q = static::active();
if($sfw) $q->sfw();
$id = $q->count() - 1;
if ($id < 0) return null;
$id = mt_rand(0, $id);
$q = static::active();
if($sfw) $q->sfw();
return $q->skip($id)->first();
}
public function scopeSfw($query) {
return $query->where('sfw', true);
}
public function scopeActive($query) {
return $query->where('until', '>=', Carbon::now());
}
}

49
app/Models/Category.php Normal file
View File

@@ -0,0 +1,49 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* App\Models\Category
*
* @property integer $id
* @property string $name
* @property string $shortname
* @property string $description
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property-read \Illuminate\Database\Eloquent\Collection|Video[] $videos
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereName($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereShortname($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Category whereDeletedAt($value)
* @property-read \Illuminate\Database\Eloquent\Collection|User[] $users
*/
class Category extends Model
{
use SoftDeletes;
protected $table = 'categories';
public function videos() {
return $this->hasMany(Video::class);
}
public function users() {
return $this->belongsToMany(User::class);
}
public function baseurl() {
return $this->shortname;
}
public function displayName() {
return e($this->name);
}
}

90
app/Models/Comment.php Normal file
View File

@@ -0,0 +1,90 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Services\Markdown;
/**
* App\Models\Comment
*
* @property integer $id
* @property string $content
* @property integer $user_id
* @property integer $video_id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property-read User $user
* @property-read Video $video
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereContent($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereVideoId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Comment whereDeletedAt($value)
*/
class Comment extends Model
{
use SoftDeletes;
protected $appends = ['rendered_view'];
public function user() {
return $this->belongsTo(User::class);
}
public function video() {
return $this->belongsTo(Video::class);
}
public static function simplemd($text) {
$m = app()->make(Markdown::class);
$text = $m->text($text);
return $text;
}
public function getRenderedViewAttribute() {
return static::simplemd($this->content);
}
public function getMentioned() {
$text = $this->content;
$nameMatcher = '/\B@([\wÄÖÜäöü]+)/i';
$ret = [];
if(preg_match_all($nameMatcher, $text, $users) > 0) {
foreach ($users[1] as $user) {
if(User::whereUsername($user)->count() > 0) {
$ret[] = User::whereUsername($user)->first();
}
}
}
return array_unique($ret);
}
public function answered() {
$text = $this->content;
$regex = '/^[!%*]*(\^+)/m';
$answers = [];
if(preg_match_all($regex, $text, $answered) > 0) {
foreach($answered[1] as $a) {
$answers[] = mb_strlen($a);
}
}
$answers = array_unique($answers);
$comments = $this->video->comments;
$total = $comments->count();
$ret = [];
foreach($answers as $c) {
$up = $total - $c - 1;
if($up >= 0) {
$ret[] = $comments->get($up)->user;
}
}
return $ret;
}
}

20
app/Models/Donation.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Donation extends Model
{
public $timestamps = false;
public static $needed = 150;
public static function getPercentage() {
return (static::getFunds() / static::$needed) * 100;
}
public static function getFunds() {
return static::sum('amount') ?? 0;
}
}

35
app/Models/Icon.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Icon extends Model
{
public $timestamps = false;
public function roles() {
return $this->hasMany(Role::class);
}
public function users() {
return $this->hasMany(User::class);
}
public function toJson($options = 0) {
return parent::toJson($options);
}
public function __toString() {
switch ($this->icon_type) {
case 'fa':
return '<i class="fa fa-' . $this->icon . '"></i>';
case 'img':
case 'image':
return '<img class="icon" src="https://s.w0bm.com/' . ltrim($this->icon, '/') . '" alt="' . $this->icon . '">';
default:
return '';
}
}
}

72
app/Models/Message.php Normal file
View File

@@ -0,0 +1,72 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* App\Models\Message
*
* @property integer $id
* @property integer $from
* @property integer $to
* @property string $content
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property string $read
* @property string $subject
* @property-read User $fromUser
* @property-read User $toUser
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereFrom($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereTo($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereContent($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereRead($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message whereSubject($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Message unread()
*/
class Message extends Model {
use SoftDeletes;
public function fromUser() {
return $this->belongsTo(User::class, 'from');
}
public function toUser() {
return $this->belongsTo(User::class, 'to');
}
public static function send($from, $to, $subject, $content) {
if(empty($subject)) return 'Subject must not be empty';
if(empty($content)) return 'Content must not be empty';
try {
if(!is_object($from))
$from = User::findOrFail($from);
if(!is_object($to))
$to = User::findOrFail($to);
} catch (ModelNotFoundException $e) {
return false;
}
$message = new static();
$message->from = $from->id;
$message->to = $to->id;
$message->subject = $subject;
$message->content = $content;
$message->save();
return $message;
}
public function scopeUnread($query) {
return $query->whereNull('read');
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* App\Models\ModeratorLog
*
* @property integer $id
* @property integer $user_id
* @property string $type
* @property string $target_type
* @property integer $target_id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property-read User $user
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereType($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereTargetType($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereTargetId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\ModeratorLog whereUpdatedAt($value)
*/
class ModeratorLog extends Model
{
public function user() {
return $this->belongsTo(User::class);
}
public function getTarget() {
$target_type = $this->target_type;
switch ($target_type) {
case 'user': return User::find($this->target_id);
case 'comment': return Comment::find($this->target_id);
case 'video': return Video::find($this->target_id);
default: return null;
}
}
}

12
app/Models/Role.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace App\Models;
use Toddish\Verify\Models\Role as VerifyRole;
class Role extends VerifyRole
{
public function icon() {
return $this->belongsTo(Icon::class, 'icon_id');
}
}

135
app/Models/User.php Normal file
View File

@@ -0,0 +1,135 @@
<?php
namespace App\Models;
use Toddish\Verify\Models\User as VerifyUser;
use Carbon\Carbon;
/**
* App\Models\User
*
* @property integer $id
* @property string $username
* @property string $password
* @property string $salt
* @property string $email
* @property string $remember_token
* @property boolean $verified
* @property boolean $disabled
* @property array $categories
* @property \Carbon\Carbon $deleted_at
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $activation_token
* @property-read \Illuminate\Database\Eloquent\Collection|Video[] $videos
* @property-read \Illuminate\Database\Eloquent\Collection|Comment[] $comments
* @property-read \Illuminate\Database\Eloquent\Collection|\config('verify.models.role')[] $roles
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereUsername($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User wherePassword($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereSalt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereEmail($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereRememberToken($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereVerified($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereDisabled($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereActivationToken($value)
* @method static \Illuminate\Database\Query\Builder|\Toddish\Verify\Models\User verified()
* @method static \Illuminate\Database\Query\Builder|\Toddish\Verify\Models\User unverified()
* @method static \Illuminate\Database\Query\Builder|\Toddish\Verify\Models\User disabled()
* @method static \Illuminate\Database\Query\Builder|\Toddish\Verify\Models\User enabled()
* @property-read \Illuminate\Database\Eloquent\Collection|ModeratorLog[] $moderator_log
* @property-read \Illuminate\Database\Eloquent\Collection|Message[] $messagesSent
* @property-read \Illuminate\Database\Eloquent\Collection|Message[] $messagesRecv
* @property-read \Illuminate\Database\Eloquent\Collection|Video[] $favs
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereBackground($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\User whereCategories($value)
*/
class User extends VerifyUser
{
protected $casts = [
// TODO: rename db column to tag filters
'categories' => 'array'
];
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
'banend'
];
public function uploads() {
return $this->hasMany(Video::class);
}
public function videos() {
return $this->uploads();
}
public function comments() {
return $this->hasMany(Comment::class);
}
public function moderator_log() {
return $this->hasMany(ModeratorLog::class);
}
public function messagesSent() {
return $this->hasMany(Message::class, 'from');
}
public function messagesRecv() {
return $this->hasMany(Message::class, 'to');
}
public function favs() {
return $this->belongsToMany(Video::class, 'favorites');
}
public function hasFaved($id) {
return ! $this->favs->filter(function($vid) use ($id) {
return $vid->id == $id;
})->isEmpty();
}
public function icon() {
return $this->belongsTo(Icon::class, 'icon_id');
}
public function activeIcon() {
$icon = $this->icon;
if($icon === null) {
$roles = $this->roles;
$roles = $roles->sortByDesc('level');
foreach($roles as $role) {
if($role !== null) $icon = $role->icon;
}
}
return $icon;
}
public function isBanned() {
if($this->disabled == 1) {
return $this->banend->eq(Carbon::createFromTimeStampUTC(1)) || $this->banend->gt(Carbon::now());
}
return false;
}
public function getForeignKey() {
return 'user_id';
}
public function baseurl() {
return 'user/' . $this->username . '/uploads';
}
public function displayName() {
return e($this->username) . ($this->activeIcon() ? " " . $this->activeIcon() : "");
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Models;
class UserFavorite extends User {
protected $table = 'users';
// Instead of uploaded Videos get favs
public function videos() {
return $this->favs();
}
public function baseurl() {
return 'user/' . $this->username . '/favs';
}
public function displayName() {
return 'Favorites (' . parent::displayName() . ')';
}
}

189
app/Models/Video.php Normal file
View File

@@ -0,0 +1,189 @@
<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* App\Models\Video
*
* @property integer $id
* @property string $file
* @property string $interpret
* @property string $songtitle
* @property string $imgsource
* @property integer $category_id
* @property integer $user_id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property string $hash
* @property-read User $user
* @property-read Category $category
* @property-read \Illuminate\Database\Eloquent\Collection|Comment[] $comments
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereFile($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereInterpret($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereSongtitle($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereImgsource($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereCategoryId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video whereHash($value)
* @property-read \Illuminate\Database\Eloquent\Collection|User[] $faved
* @property-read \Illuminate\Database\Eloquent\Collection|Tag[] $tags
* @property-read mixed $tag_list
* @property-read mixed $tag_list_normalized
* @property-read mixed $tag_array
* @property-read mixed $tag_array_normalized
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video newlyups()
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video withAllTags($tags)
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video withAnyTags($tags = array())
* @method static \Illuminate\Database\Query\Builder|\App\Models\Video withoutTags()
*/
class Video extends Model
{
use SoftDeletes;
use \Cviebrock\EloquentTaggable\Taggable;
public function user() {
return $this->belongsTo(User::class);
}
public function category() {
return $this->belongsTo(Category::class);
}
public function comments() {
return $this->hasMany(Comment::class);
}
public function faved() {
return $this->belongsToMany(User::class, 'favorites', 'video_id', 'user_id');
}
public static function getFirstId($related = null) {
if ($related) {
return $related->videos()->filtered()->orderBy('id', 'ASC')->first()->id;
}
return static::filtered()->orderBy('id', 'ASC')->first()->id;
}
public static function getLastId($related = null) {
if ($related) {
return $related->videos()->filtered()->orderBy('id', 'DESC')->first()->id;
}
return static::select('id')->filtered()->orderBy('id', 'DESC')->first()->id;
}
public function getNext($related = null) {
if ($related) {
return $related->videos()->filtered()->where('id', '>', $this->id)->orderBy('id', 'ASC')->first();
} else {
return static::filtered()->where('id', '>', $this->id)->orderBy('id', 'ASC')->first();
}
}
public function getPrev($related = null) {
if ($related) {
return $related->videos()->filtered()->where('id', '<', $this->id)->orderBy('id', 'DESC')->first();
} else {
return static::filtered()->where('id', '<', $this->id)->orderBy('id', 'DESC')->first();
}
}
public function scopeNewlyups($query) {
return $query->where('created_at', '>=', Carbon::now()->subHours(12));
}
public function scopeFiltered($query) {
if(auth()->check()) {
// TODO rename to filtered
$filter = auth()->user()->categories;
if(empty($filter))
return $query;
return $query->withoutAnyTags($filter);
} else {
// TODO: filter if post has sfw & nsfw tags
//return $query->withAllTags('sfw');
return $query->withoutAnyTags('nsfw');
}
}
public function checkFileEncoding() {
$dat = $this->file;
$in = public_path() . "/b";
$tmpdir = str_replace("public", "app/Http/Controllers/tmp", public_path());
for($i = 0; $i < 2; $i++) {
$ret = shell_exec("ffmpeg -y -ss 0 -i {$in}/{$dat} -vframes 1 {$tmpdir}/test.png 2>&1");
if(strpos($ret, "nothing was encoded") !== false) {
shell_exec("ffmpeg -i {$in}/{$dat} -map 0:0 -map 0:1 -c:v copy {$tmpdir}/{$dat}");
unlink($in . "/" . $dat);
rename($tmpdir . "/" . $dat, $in . "/" . $dat);
}
else return true;
}
return false;
}
/**
* Creates a .gif thumbnail to a given video file
*
* @param string $dat File of the video
*/
public function createThumbnail() {
$dat = $this->file;
$in = public_path() . "/b"; // webm-input
$out = public_path() . "/thumbs"; //thumb-output
$tmpdir = str_replace("public", "app/Http/Controllers/tmp", public_path());
$name = explode(".", $dat);
array_pop($name);
$name = join(".", $name);
if(!file_exists("{$out}/{$name}.gif")) {
$length = round(shell_exec("ffprobe -i {$in}/{$dat} -show_format -v quiet | sed -n 's/duration=//p'"));
for ($i = 1; $i < 10; $i++) {
$act = ($i * 10) * ($length / 100);
$ffmpeg = shell_exec("ffmpeg -ss {$act} -i {$in}/{$dat} -vf \"scale='if(gt(a,4/3),206,-1)':'if(gt(a,4/3),-1,116)'\" -vframes 1 {$tmpdir}/{$name}_{$i}.png 2>&1");
}
$tmp = shell_exec("convert -delay 27 -loop 0 {$tmpdir}/{$name}_*.png {$out}/{$name}.gif 2>&1");
if(@filesize("{$out}/{$name}.gif") < 2000)
@unlink("{$out}/{$name}.gif");
array_map('unlink', glob("{$tmpdir}/{$name}*.png"));
}
}
public static function getRandom($related = null) {
if ($related) {
$id = $related->videos()->filtered()->countScoped()->count() - 1;
if ($id < 0) {
return redirect()->back()->with('error', 'no videos found');
}
$id = mt_rand(0, $id);
return $related->videos()->filtered()->skip($id);
}
$id = static::filtered()->countScoped()->count() - 1;
if ($id < 0) {
return redirect()->back()->with('error', 'no videos found');
}
$id = mt_rand(0, $id);
return static::filtered()->skip($id);
}
public function isSfw() {
return $this->tags->contains(function ($key, $tag) {
$tag->normalized === 'sfw';
});
}
public function filesize() {
return filesize(getcwd() . "/b/" . $this->file);
}
}

0
app/Policies/.gitkeep Normal file
View File

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Providers;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any application authentication / authorization services.
*
* @param \Illuminate\Contracts\Auth\Access\Gate $gate
* @return void
*/
public function boot(GateContract $gate)
{
parent::registerPolicies($gate);
//
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Blade;
class BladeServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
/* @simplemd($var) */
/** @var \Illuminate\View\Compilers\BladeCompiler $compiler */
Blade::directive('simplemd', function($text) {
return "<?php echo App\\Models\\Comment::simplemd({$text}); ?>";
});
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
//
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
];
/**
* Register any other events for your application.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
//
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\Markdown;
class MarkdownServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Markdown::class, function ($app) {
return Markdown::instance();
});
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Providers;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to the controller routes in your routes file.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot(Router $router)
{
//
parent::boot($router);
}
/**
* Define the routes for the application.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
});
}
}

340
app/Services/Markdown.php Normal file
View File

@@ -0,0 +1,340 @@
<?php
namespace App\Services;
use App\Models\User;
class Markdown extends \Parsedown {
function __construct() {
$this->setMarkupEscaped(true);
$this->setBreaksEnabled(true);
$this->setUrlsLinked(true);
$this->InlineTypes['@'][] = 'UserMention';
#$this->InlineTypes['%'][] = 'ColoredText';
$this->InlineTypes['['][] = 'KrebsText';
$this->InlineTypes['['][] = 'ReichText';
$this->InlineTypes['['][] = 'RainbowText';
$this->InlineTypes['['][] = 'SpoilerText';
$this->InlineTypes[':'][] = 'emojimatcherpng';
//$this->InlineTypes[':'][] = 'emojimatchermp4';
$this->InlineTypes[':'][] = 'ClickableTimestamp';
$this->inlineMarkerList .= '@';
}
protected function paragraph($Line) {
$Block = array(
'element' => array(
'name' => 'p',
'text' => $Line['text'],
'handler' => 'line',
'attributes' => [
'class' => 'comment'
]
),
);
return $Block;
}
// Matches the emojis in png format
protected function inlineemojimatcherpng($Excerpt) {
if (preg_match('/\:(\w+)\:/mUs', $Excerpt['text'], $matches)) {
$path = "images/comments/" . $matches[1];
$file_ext = "";
if(file_exists($path . ".png"))
$file_ext = ".png";
else if(file_exists($path . ".gif"))
$file_ext = ".gif";
if($file_ext === "")
return;
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'img',
'handler' => 'line',
'attributes' => [
'class' => 'comment_emoji',
'src' => '//s.w0bm.com/images/comments/' . $matches[1] . $file_ext,
'alt' => ':' . $matches[1] . ':',
'title' => ':' . $matches[1] . ':'
],
]
];
}
}
// Matches MP4 Emojis (Currently not possible due to Chromes shitty and malfunctioning autplay policy. Thanks idiots :*)
//protected function inlineemojimatchermp4($Excerpt) {
// if (preg_match('/\:(uwe)\:/mUs', $Excerpt['text'], $matches)) {
// return [
// 'extent' => strlen($matches[0]),
// 'element' => [
// 'name' => 'video',
// 'handler' => 'line',
// 'attributes' => [
// 'loop' => 'true',
// 'autoplay' => 'true',
// 'muted' => '',
// 'class' => 'comment_video',
// 'src' => '/images/comments/' . $matches[1] . '.mp4'
// ],
// ]
// ];
// }
//}
protected function inlineUserMention($Excerpt) {
if (preg_match('/\B@([\wÄÖÜäöü]+)/i', $Excerpt['context'], $matches)) {
if(User::whereUsername($matches[1])->count() > 0) {
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'a',
'text' => $matches[0],
'attributes' => [
'href' => '/user/' . $matches[1], //link to username profile
'class' => 'user-mention', //style class of url
],
],
];
} else {
return [
'markup' => $matches[0],
'extent' => strlen($matches[0]),
];
}
}
}
// Matches [rb][/rb]
protected function inlineRainbowText($Excerpt) {
if (preg_match('/\[rb\](.+)\[\/rb]/mUs', $Excerpt['text'], $matches)) {
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'span',
'handler' => 'line',
'text' => $matches[1],
'attributes' => [
'class' => 'rainbow'
],
]
];
}
}
// Matches [spoiler][/spoiler]
protected function inlineSpoilerText($Excerpt) {
if (preg_match('/\[spoiler\](.+)\[\/spoiler]/mUs', $Excerpt['text'], $matches)) {
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'span',
'handler' => 'line',
'text' => $matches[1],
'attributes' => [
'class' => 'spoiler'
],
]
];
}
}
// Matches [krebs][/krebs]
protected function inlineKrebsText($Excerpt) {
if (preg_match('/\[krebs\](.+)\[\/krebs]/mUs', $Excerpt['text'], $matches)) {
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'span',
'handler' => 'line',
'text' => $matches[1],
'attributes' => [
'class' => 'anim'
],
]
];
}
}
// Matches Reichtext
protected function inlineReichText($Excerpt) {
if (preg_match('/\[reich\](.+)\[\/reich]/mUs', $Excerpt['text'], $matches)) {
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'span',
'handler' => 'line',
'text' => $matches[1],
'attributes' => [
'class' => 'reich'
],
]
];
}
}
// Matches %text% <- literally wtf error
/*protected function inlineColoredText($Excerpt) {
if (preg_match('/%(.+)%/', $Excerpt['text'], $matches)) {
return [
'extent' => strlen($matches[0]),
'element' => [
'name' => 'span',
'text' => $matches[1],
'attributes' => [
'class' => ''
],
]
];
}
}*/
//Greentext
protected function blockQuote($Excerpt) {
if (preg_match('/^>[ ]?(.*)/', $Excerpt['text'], $matches)) {
$Block = [
'element' => [
'name' => 'blockquote',
'handler' => 'lines',
'text' => (array) ('&gt;' . $matches[1]),
],
];
return $Block;
}
}
protected function blockQuoteContinue($Excerpt, array $Block) {
if ($Excerpt['text'][0] === '>' && preg_match('/^>[ ]?(.*)/', $Excerpt['text'], $matches)) {
if (isset($Block['interrupted'])) {
$Block['element']['text'][] = '';
unset($Block['interrupted']);
}
$Block['element']['text'][] = '&gt;' . $matches[1];
return $Block;
}
if (!isset($Block['interrupted'])) {
$Block['element']['text'][] = '&gt;' . $Excerpt['text'];
return $Block;
}
}
// Disable Lists
protected function blockList($Excerpt) {
return;
}
protected function blockListContinue($Excerpt, array $block) {
return;
}
// Disable headers
protected function blockHeader($Excerpt) {
return;
}
protected function blockSetextHeader($Excerpt, array $block = null) {
return;
}
protected function blockTable($Excerpt, array $block = null) {
return;
}
// Disable markdown links
protected function inlineLink($Excerpt) {
return;
}
// Disable markdown images
protected function inlineImage($Excerpt) {
return;
}
// Differentiate between internal and external urls and images
protected function inlineUrl($Excerpt) {
$e = parent::inlineUrl($Excerpt);
if (is_null($e)) return;
if (static::isImage($e['element']['attributes']['href'])) {
$e['element']['name'] = 'img';
$e['element']['attributes']['src'] = $e['element']['attributes']['href'];
$e['element']['attributes']['alt'] = 'Image';
$e['element']['attributes']['class'] = 'comment_image';
unset($e['element']['attributes']['href']);
unset($e['element']['text']);
return $e;
}
if (!static::isInternal($e['element']['attributes']['href'])) {
$e['element']['attributes']['target'] = '_blank';
$e['element']['attributes']['rel'] = 'extern';
} else {
$url = parse_url($e['element']['text']);
$text = $url['path'];
if (isset($url['query'])) {
$text .= '?' . $url['query'];
}
if (isset($url['fragment'])) {
$text .= '#' . $url['fragment'];
}
$e['element']['text'] = $text;
}
return $e;
}
protected function inlineClickableTimestamp($Excerpt) {
if (preg_match('/(?<=\s|^)([0-5]?\d:[0-5]\d)(?=\s|$)/', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) {
return [
'extent' => strlen($matches[0][0]),
'position' => $matches[0][1],
'element' => [
'name' => 'a',
'text' => $matches[0][0],
'attributes' => [
'href' => '#',
'class' => 'comment_clickable_timestamp'
]
]
];
}
}
private static function isInternal($url) {
$host = parse_url($url, PHP_URL_HOST);
$currhost = $_SERVER['SERVER_NAME'];
if (0 === strpos($host, 'www')) {
$host = substr($host, 4);
}
if (0 === strpos($currhost, 'www')) {
$currhost = substr($currhost, 4);
}
return $host === $currhost;
}
private static function isImage($url) {
$cfg = config('comments');
$allowedHosters = $cfg['allowedHosters'];
$allowedExtensions = $cfg['allowedImageFileExtensions'];
$url = parse_url($url);
if (isset($url['path'])) {
$ext = pathinfo($url['path'], PATHINFO_EXTENSION);
if (in_array($ext, $allowedExtensions)) {
if (isset($url['scheme']) && $url['scheme'] === 'https') {
foreach($allowedHosters as $hoster) {
foreach($hoster as $regex) {
if(preg_match($regex, $url['host'])) {
return true;
}
}
}
return false;
}
}
}
return false;
}
}