diff options
| author | dev | 2026-06-27 05:34:00 +0200 |
|---|---|---|
| committer | dev | 2026-06-27 05:34:00 +0200 |
| commit | b608ced142cd0527906b554e04376292f718f084 (patch) | |
| tree | 6f6937b35b902db3f0bca6476000dd61e3fcc85d /ssh/app | |
| parent | 0fe83c7f76b2fd6ce79541a71cdde5ec0b12becf (diff) | |
| parent | 043dd3ed90cac67975996bd881a997f38679bacd (diff) | |
| download | curious-b608ced142cd0527906b554e04376292f718f084.tar.gz | |
Merged cinema into mostdiscussed.com
Diffstat (limited to 'ssh/app')
32 files changed, 1729 insertions, 0 deletions
diff --git a/ssh/app/Article.php b/ssh/app/Article.php new file mode 100644 index 0000000..9f11ea3 --- /dev/null +++ b/ssh/app/Article.php @@ -0,0 +1,23 @@ +<?php + +namespace App; + +use Illuminate\Database\Eloquent\Model; + +class Article extends Model +{ + protected $table = "view_article"; + + protected $fillable = [ + ]; + + public function getDiscussions() { + #return $this->hasMany('App\Discussion', 'article_id', 'id'); + return $this->hasMany('App\Discussion'); + } + + public function getCategories() { + return $this->belongsToMany('App\Category', 'article_category'); + } +} + diff --git a/ssh/app/Category.php b/ssh/app/Category.php new file mode 100644 index 0000000..7f0cdb2 --- /dev/null +++ b/ssh/app/Category.php @@ -0,0 +1,18 @@ +<?php + +namespace App; + +use Illuminate\Database\Eloquent\Model; + +class Category extends Model +{ + protected $table = "category"; + protected $fillable = [ + 'id', + 'name' + ]; + + public function getArticles(){ + return $this->belongsToMany('App\Article', 'article_category'); + } +} diff --git a/ssh/app/Console/Commands/GenerateSitemap.php b/ssh/app/Console/Commands/GenerateSitemap.php new file mode 100644 index 0000000..46bb0ac --- /dev/null +++ b/ssh/app/Console/Commands/GenerateSitemap.php @@ -0,0 +1,52 @@ +<?php + +namespace App\Console\Commands; + +use Illuminate\Console\Command; +use Spatie\Sitemap\SitemapGenerator; +use Psr\Http\Message\UriInterface; + +class GenerateSitemap extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'sitemap:generate'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Generate the sitemap'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // modify this to your own needs + SitemapGenerator::create(config('app.url')) + ->shouldCrawl(function (UriInterface $url) { + /** + * Prevent the crawler from crawling the random pages. + */ + return strpos($url->getPath(), '/random') === false; + }) + ->writeToFile(public_path('sitemap.xml')); + } +} diff --git a/ssh/app/Console/Kernel.php b/ssh/app/Console/Kernel.php new file mode 100644 index 0000000..69914e9 --- /dev/null +++ b/ssh/app/Console/Kernel.php @@ -0,0 +1,41 @@ +<?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 = [ + // + ]; + + /** + * Define the application's command schedule. + * + * @param \Illuminate\Console\Scheduling\Schedule $schedule + * @return void + */ + protected function schedule(Schedule $schedule) + { + // $schedule->command('inspire')->hourly(); + } + + /** + * Register the commands for the application. + * + * @return void + */ + protected function commands() + { + $this->load(__DIR__.'/Commands'); + + require base_path('routes/console.php'); + } +} diff --git a/ssh/app/Discussion.php b/ssh/app/Discussion.php new file mode 100644 index 0000000..facb847 --- /dev/null +++ b/ssh/app/Discussion.php @@ -0,0 +1,24 @@ +<?php + +namespace App; + +use Illuminate\Database\Eloquent\Model; + +class Discussion extends Model +{ + protected $table = "discussion"; + protected $fillable = [ + 'article_id', + 'title', + 'source', + 'item_id', + 'source_url', + 'posted_on', + 'comments', + 'upvotes' + ]; + + public function getArticle() { + $this->belongsTo('App\Article'); + } +} diff --git a/ssh/app/Exceptions/Handler.php b/ssh/app/Exceptions/Handler.php new file mode 100644 index 0000000..59c585d --- /dev/null +++ b/ssh/app/Exceptions/Handler.php @@ -0,0 +1,55 @@ +<?php + +namespace App\Exceptions; + +use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; +use Throwable; + +class Handler extends ExceptionHandler +{ + /** + * A list of the exception types that are not reported. + * + * @var array + */ + protected $dontReport = [ + // + ]; + + /** + * A list of the inputs that are never flashed for validation exceptions. + * + * @var array + */ + protected $dontFlash = [ + 'password', + 'password_confirmation', + ]; + + /** + * Report or log an exception. + * + * @param \Throwable $exception + * @return void + * + * @throws \Exception + */ + public function report(Throwable $exception) + { + parent::report($exception); + } + + /** + * Render an exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @param \Throwable $exception + * @return \Symfony\Component\HttpFoundation\Response + * + * @throws \Throwable + */ + public function render($request, Throwable $exception) + { + return parent::render($request, $exception); + } +} diff --git a/ssh/app/Http/Controllers/Auth/ConfirmPasswordController.php b/ssh/app/Http/Controllers/Auth/ConfirmPasswordController.php new file mode 100644 index 0000000..138c1f0 --- /dev/null +++ b/ssh/app/Http/Controllers/Auth/ConfirmPasswordController.php @@ -0,0 +1,40 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Providers\RouteServiceProvider; +use Illuminate\Foundation\Auth\ConfirmsPasswords; + +class ConfirmPasswordController extends Controller +{ + /* + |-------------------------------------------------------------------------- + | Confirm Password Controller + |-------------------------------------------------------------------------- + | + | This controller is responsible for handling password confirmations and + | uses a simple trait to include the behavior. You're free to explore + | this trait and override any functions that require customization. + | + */ + + use ConfirmsPasswords; + + /** + * Where to redirect users when the intended url fails. + * + * @var string + */ + protected $redirectTo = RouteServiceProvider::HOME; + + /** + * Create a new controller instance. + * + * @return void + */ + public function __construct() + { + $this->middleware('auth'); + } +} diff --git a/ssh/app/Http/Controllers/Auth/ForgotPasswordController.php b/ssh/app/Http/Controllers/Auth/ForgotPasswordController.php new file mode 100644 index 0000000..465c39c --- /dev/null +++ b/ssh/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -0,0 +1,22 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Foundation\Auth\SendsPasswordResetEmails; + +class ForgotPasswordController extends Controller +{ + /* + |-------------------------------------------------------------------------- + | Password Reset Controller + |-------------------------------------------------------------------------- + | + | This controller is responsible for handling password reset emails and + | includes a trait which assists in sending these notifications from + | your application to your users. Feel free to explore this trait. + | + */ + + use SendsPasswordResetEmails; +} diff --git a/ssh/app/Http/Controllers/Auth/LoginController.php b/ssh/app/Http/Controllers/Auth/LoginController.php new file mode 100644 index 0000000..18a0d08 --- /dev/null +++ b/ssh/app/Http/Controllers/Auth/LoginController.php @@ -0,0 +1,40 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Providers\RouteServiceProvider; +use Illuminate\Foundation\Auth\AuthenticatesUsers; + +class LoginController extends Controller +{ + /* + |-------------------------------------------------------------------------- + | Login Controller + |-------------------------------------------------------------------------- + | + | This controller handles authenticating users for the application and + | redirecting them to your home screen. The controller uses a trait + | to conveniently provide its functionality to your applications. + | + */ + + use AuthenticatesUsers; + + /** + * Where to redirect users after login. + * + * @var string + */ + protected $redirectTo = RouteServiceProvider::HOME; + + /** + * Create a new controller instance. + * + * @return void + */ + public function __construct() + { + $this->middleware('guest')->except('logout'); + } +} diff --git a/ssh/app/Http/Controllers/Auth/RegisterController.php b/ssh/app/Http/Controllers/Auth/RegisterController.php new file mode 100644 index 0000000..c6a6de6 --- /dev/null +++ b/ssh/app/Http/Controllers/Auth/RegisterController.php @@ -0,0 +1,73 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Providers\RouteServiceProvider; +use App\User; +use Illuminate\Foundation\Auth\RegistersUsers; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Validator; + +class RegisterController extends Controller +{ + /* + |-------------------------------------------------------------------------- + | Register Controller + |-------------------------------------------------------------------------- + | + | This controller handles the registration of new users as well as their + | validation and creation. By default this controller uses a trait to + | provide this functionality without requiring any additional code. + | + */ + + use RegistersUsers; + + /** + * Where to redirect users after registration. + * + * @var string + */ + protected $redirectTo = RouteServiceProvider::HOME; + + /** + * Create a new controller instance. + * + * @return void + */ + public function __construct() + { + $this->middleware('guest'); + } + + /** + * Get a validator for an incoming registration request. + * + * @param array $data + * @return \Illuminate\Contracts\Validation\Validator + */ + protected function validator(array $data) + { + return Validator::make($data, [ + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], + 'password' => ['required', 'string', 'min:8', 'confirmed'], + ]); + } + + /** + * Create a new user instance after a valid registration. + * + * @param array $data + * @return \App\User + */ + protected function create(array $data) + { + return User::create([ + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => Hash::make($data['password']), + ]); + } +} diff --git a/ssh/app/Http/Controllers/Auth/ResetPasswordController.php b/ssh/app/Http/Controllers/Auth/ResetPasswordController.php new file mode 100644 index 0000000..b1726a3 --- /dev/null +++ b/ssh/app/Http/Controllers/Auth/ResetPasswordController.php @@ -0,0 +1,30 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Providers\RouteServiceProvider; +use Illuminate\Foundation\Auth\ResetsPasswords; + +class ResetPasswordController extends Controller +{ + /* + |-------------------------------------------------------------------------- + | Password Reset Controller + |-------------------------------------------------------------------------- + | + | This controller is responsible for handling password reset requests + | and uses a simple trait to include this behavior. You're free to + | explore this trait and override any methods you wish to tweak. + | + */ + + use ResetsPasswords; + + /** + * Where to redirect users after resetting their password. + * + * @var string + */ + protected $redirectTo = RouteServiceProvider::HOME; +} diff --git a/ssh/app/Http/Controllers/Auth/VerificationController.php b/ssh/app/Http/Controllers/Auth/VerificationController.php new file mode 100644 index 0000000..5e749af --- /dev/null +++ b/ssh/app/Http/Controllers/Auth/VerificationController.php @@ -0,0 +1,42 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Providers\RouteServiceProvider; +use Illuminate\Foundation\Auth\VerifiesEmails; + +class VerificationController extends Controller +{ + /* + |-------------------------------------------------------------------------- + | Email Verification Controller + |-------------------------------------------------------------------------- + | + | This controller is responsible for handling email verification for any + | user that recently registered with the application. Emails may also + | be re-sent if the user didn't receive the original email message. + | + */ + + use VerifiesEmails; + + /** + * Where to redirect users after verification. + * + * @var string + */ + protected $redirectTo = RouteServiceProvider::HOME; + + /** + * Create a new controller instance. + * + * @return void + */ + public function __construct() + { + $this->middleware('auth'); + $this->middleware('signed')->only('verify'); + $this->middleware('throttle:6,1')->only('verify', 'resend'); + } +} diff --git a/ssh/app/Http/Controllers/CinemaController.php b/ssh/app/Http/Controllers/CinemaController.php new file mode 100644 index 0000000..75c93aa --- /dev/null +++ b/ssh/app/Http/Controllers/CinemaController.php @@ -0,0 +1,233 @@ +<?php + +namespace App\Http\Controllers; + +use Illuminate\Support\Facades\DB; +use Illuminate\Http\Request; + +class CinemaController extends Controller +{ + public function cinema(Request $request) + { + $order = $request->input('order', 'ref_count'); + $direction = $request->input('direction', 'desc'); + $validOrders = ['ref_count', 'score', 'num_votes', 'num_accolades', 'start_year']; + $validDirections = ['asc', 'desc']; + if (! in_array($order, $validOrders)) { + $order = 'ref_count'; + } + if (! in_array($direction, $validDirections)) { + $direction = 'desc'; + } + + $refCounts = DB::connection('cinema') + ->table('links') + ->select('links.param', DB::raw('COUNT(*) as ref_count')) + ->where('links.host', 'www.imdb.com') + ->where('links.field', 1) + ->groupBy('links.param'); + + $movies = DB::connection('cinema') + ->table('imdb') + ->select( + 'imdb.id', + 'imdb.imdb_id', + 'imdb.primary_title', + 'imdb.original_title', + 'imdb.start_year', + 'imdb.average_rating', + 'imdb.num_votes', + 'imdb.synopsis', + 'imdb.poster_url', + 'imdb.title_type', + 'imdb.runtime_minutes', + 'imdb.has_people', + 'imdb.average_rating as score', + 'imdb.num_accolades', + DB::raw('COALESCE(ref.ref_count, 0) as ref_count') + ) + ->leftJoinSub($refCounts, 'ref', function ($join) { + $join->on('ref.param', '=', 'imdb.imdb_id'); + }) + ->whereNotNull('imdb.primary_title') + ->whereNotNull('imdb.wiki_article') + ->where('imdb.title_type', 'movie') + ->orderBy($order, $direction) + ->simplePaginate(12); + + $total = DB::connection('cinema') + ->table('imdb') + ->whereNotNull('primary_title') + ->whereNotNull('wiki_article') + ->where('title_type', 'movie') + ->count(); + + return view('cinema', ['movies' => $movies, 'count' => $total, 'order' => $order, 'direction' => $direction]); + } + + public function show($id) + { + $movie = DB::connection('cinema') + ->table('imdb') + ->where('imdb.imdb_id', $id) + ->first(); + + if (! $movie) { + abort(404); + } + + $genres = DB::connection('cinema') + ->table('imdb_genre') + ->join('genre', 'genre.id', '=', 'imdb_genre.genre_id') + ->where('imdb_genre.imdb_id', $movie->id) + ->pluck('genre.name'); + + $casts = DB::connection('cinema') + ->table('who') + ->join('people', 'people.id', '=', 'who.people_id') + ->join('profession', 'profession.id', '=', 'who.profession_id') + ->where('who.imdb_id', $movie->id) + ->select('people.name', 'profession.name as profession') + ->get(); + + $actors = $casts->where('profession', 'actor')->take(8); + $directors = $casts->where('profession', 'director'); + $screenwriters = $casts->where('profession', 'screenwriter')->take(3); + + $hnStories = DB::connection('cinema') + ->table('links') + ->join('story', 'story.id', '=', 'links.story_id') + ->select( + 'story.story_id', + 'story.title', + 'story.type', + 'story.text', + 'story.score', + 'story.descendants', + 'story.time' + ) + ->where('links.host', 'www.imdb.com') + ->where('links.field', 1) + ->where('links.param', $id) + ->orderBy('story.time', 'desc') + ->get(); + + return view('cinema_show', [ + 'movie' => $movie, + 'genres' => $genres, + 'actors' => $actors, + 'directors' => $directors, + 'screenwriters' => $screenwriters, + 'hnStories' => $hnStories, + ]); + } + + public function genres() + { + $genres = DB::connection('cinema') + ->table('genre') + ->select('genre.name', DB::raw('COUNT(imdb_genre.imdb_id) as count')) + ->join('imdb_genre', 'imdb_genre.genre_id', '=', 'genre.id') + ->join('imdb', 'imdb.id', '=', 'imdb_genre.imdb_id') + ->whereNotNull('imdb.primary_title') + ->whereNotNull('imdb.wiki_article') + ->where('imdb.title_type', 'movie') + ->groupBy('genre.name') + ->orderBy('count', 'desc') + ->get(); + + return view('genres', ['genres' => $genres]); + } + + public function genre($name) + { + $genre = DB::connection('cinema') + ->table('genre') + ->where('name', $name) + ->first(); + + if (! $genre) { + abort(404); + } + + $movies = DB::connection('cinema') + ->table('imdb') + ->select( + 'imdb.id', + 'imdb.imdb_id', + 'imdb.primary_title', + 'imdb.original_title', + 'imdb.start_year', + 'imdb.average_rating', + 'imdb.num_votes', + 'imdb.synopsis', + 'imdb.poster_url', + 'imdb.title_type', + 'imdb.runtime_minutes' + ) + ->join('imdb_genre', 'imdb_genre.imdb_id', '=', 'imdb.id') + ->join('genre', 'genre.id', '=', 'imdb_genre.genre_id') + ->where('genre.name', $name) + ->whereNotNull('imdb.primary_title') + ->whereNotNull('imdb.wiki_article') + ->where('imdb.title_type', 'movie') + ->orderBy('imdb.average_rating', 'desc') + ->simplePaginate(12); + + $count = DB::connection('cinema') + ->table('imdb') + ->join('imdb_genre', 'imdb_genre.imdb_id', '=', 'imdb.id') + ->join('genre', 'genre.id', '=', 'imdb_genre.genre_id') + ->where('genre.name', $name) + ->whereNotNull('imdb.primary_title') + ->whereNotNull('imdb.wiki_article') + ->where('imdb.title_type', 'movie') + ->count(); + + return view('genre_movies', ['movies' => $movies, 'count' => $count, 'genre_name' => $name]); + } + + public function search(Request $request) + { + $query = $request->input('q', ''); + + $movies = DB::connection('cinema') + ->table('imdb') + ->select( + 'imdb.id', + 'imdb.imdb_id', + 'imdb.primary_title', + 'imdb.original_title', + 'imdb.start_year', + 'imdb.average_rating', + 'imdb.num_votes', + 'imdb.synopsis', + 'imdb.poster_url', + 'imdb.title_type', + 'imdb.runtime_minutes' + ) + ->whereNotNull('imdb.primary_title') + ->whereNotNull('imdb.wiki_article') + ->where('imdb.title_type', 'movie') + ->where(function ($q) use ($query) { + $q->where('imdb.primary_title', 'like', '%' . $query . '%') + ->orWhere('imdb.original_title', 'like', '%' . $query . '%') + ->orWhere('imdb.synopsis', 'like', '%' . $query . '%'); + }) + ->simplePaginate(12); + + $total = DB::connection('cinema') + ->table('imdb') + ->whereNotNull('primary_title') + ->whereNotNull('wiki_article') + ->where('title_type', 'movie') + ->where(function ($q) use ($query) { + $q->where('primary_title', 'like', '%' . $query . '%') + ->orWhere('original_title', 'like', '%' . $query . '%') + ->orWhere('synopsis', 'like', '%' . $query . '%'); + }) + ->count(); + + return view('cinema', ['movies' => $movies, 'count' => $total, 'search_query' => $query]); + } +} diff --git a/ssh/app/Http/Controllers/Controller.php b/ssh/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..a0a2a8a --- /dev/null +++ b/ssh/app/Http/Controllers/Controller.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Http\Controllers; + +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 +{ + use AuthorizesRequests, DispatchesJobs, ValidatesRequests; +} diff --git a/ssh/app/Http/Controllers/FeedController.php b/ssh/app/Http/Controllers/FeedController.php new file mode 100644 index 0000000..9d20fce --- /dev/null +++ b/ssh/app/Http/Controllers/FeedController.php @@ -0,0 +1,97 @@ +<?php + +namespace App\Http\Controllers; + +use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use App\Article; +use App\Discussion; +use App\Category; +use App\Libraries\Helper; + +class FeedController extends Controller +{ + + public function new() + { + // creating rss feed with our most recent 20 posts + $articles = Article::join('discussion', 'discussion.article_id', '=', 'view_article.id') + ->select('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->groupBy('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->where('view_article.created_at', '<', now()->subMinutes(30)) + ->orderByRaw('MAX(discussion.posted_on) DESC') + ->take(20) + ->get(); + + return Helper::makeFeed($articles, "new"); + } + + public function mastodon() + { + $articles = Article::join('discussion', 'discussion.article_id', '=', 'view_article.id') + ->select('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->groupBy('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->where('view_article.created_at', '<', now()->subMinutes(30)) + ->orderByRaw('MAX(discussion.posted_on) DESC') + ->take(20) + ->get(); + return Helper::makeFeed($articles, "mastodon"); + } + public function mastodon_test() + { + $articles = Article::join('discussion', 'discussion.article_id', '=', 'view_article.id') + ->select('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->groupBy('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->where('view_article.created_at', '<', now()->subMinutes(30)) + ->orderByRaw('MAX(discussion.posted_on) DESC') + ->take(20) + ->get(); + return Helper::makeFeed($articles, "mastodon_test"); + } + + public function popular() + { + + $articles = new Article; + $articles = $articles->setTable('view_popular'); + $articles = $articles->take(20)->get(); + return Helper::makeFeed($articles, "popular"); + } + + public function search(Request $request) { + $search_unsafe = $request->input("q"); + + if ( "" == $search_unsafe ) { + $search_unsafe = ""; + } + + $search_unsafe = explode(",", $request->input("q")); + + $articles = new Article; + + if ( "on" == $request->input("onlypopular") ) { + $articles = $articles->setTable('view_popular'); + } + + foreach($search_unsafe as $q) { + $q = Helper::escapeLike($q); + $q = "%".$q."%"; + $articles = $articles->where(function ($query) use ($q) { + $query->whereHas('getCategories', function ($query) use ($q){ + $query->where('name', 'like', $q); + }) + ->orWhere('title', 'like', $q) + ->orWhere('url', 'like', $q) + ->orWhere('excerpt_html', 'like', $q); + }); + } + $count = $articles->count(); + + if ( "on" == $request->input("onlypopular") ) { + $articles = $articles->orderBy('impact', 'desc'); + } + $articles = $articles->orderBy('created_at', 'desc'); + + return Helper::makeFeed($articles->take(20)->get(), $request->input("q")); + } +} diff --git a/ssh/app/Http/Controllers/HomeController.php b/ssh/app/Http/Controllers/HomeController.php new file mode 100644 index 0000000..7cbc2c3 --- /dev/null +++ b/ssh/app/Http/Controllers/HomeController.php @@ -0,0 +1,28 @@ +<?php + +namespace App\Http\Controllers; + +use Illuminate\Http\Request; + +class HomeController extends Controller +{ + /** + * Create a new controller instance. + * + * @return void + */ + public function __construct() + { + $this->middleware('auth'); + } + + /** + * Show the application dashboard. + * + * @return \Illuminate\Contracts\Support\Renderable + */ + public function index() + { + return view('home'); + } +} diff --git a/ssh/app/Http/Controllers/IndexController.php b/ssh/app/Http/Controllers/IndexController.php new file mode 100644 index 0000000..7e7b31b --- /dev/null +++ b/ssh/app/Http/Controllers/IndexController.php @@ -0,0 +1,150 @@ +<?php + +namespace App\Http\Controllers; + +use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use App\Article; +use App\Discussion; +use App\Category; +use App\Libraries\Helper; + +class IndexController extends Controller +{ + + public function index() + { + return view('index'); + } + + public function about() + { + $count_articles = DB::Select("SELECT COUNT(*) as count FROM article;")[0]; + $count_discussions = DB::Select("SELECT COUNT(*) as count FROM discussion;")[0]; + $count_comments = DB::Select("SELECT sum(comments) as count FROM discussion;")[0]; + $count_upvotes = DB::Select("SELECT sum(upvotes) as count FROM discussion;")[0]; + return view('about', [ + "count_articles" => $count_articles->count, + "count_discussions" => $count_discussions->count, + "count_comments" => number_format($count_comments->count), + "count_upvotes" => number_format($count_upvotes->count)]); + } + + public function topic( $topic ) + { + $articles = new Category; + $articles = $articles->orWhere('name', $topic); + $articles = $articles->get()->first(); + if ( is_null($articles) ) { + abort(404); + } + $articles = $articles->getArticles(); + $articles = $articles->orderBy('impact', 'desc'); + $count = $articles->count(); + $articles = $articles->simplePaginate(10); + + return view('list', ["articles" => $articles, "count" => $count]); + } + + public function new() + { + $articles = Article::join('discussion', 'discussion.article_id', '=', 'view_article.id') + ->select('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->groupBy('view_article.id', 'view_article.article_id', 'view_article.url', 'view_article.title', 'view_article.excerpt_html', 'view_article.impact', 'view_article.upvotes', 'view_article.comments', 'view_article.repost') + ->orderByRaw('MAX(discussion.posted_on) DESC'); + + $count = $articles->count(); + $articles = $articles->simplePaginate(10); + + return view('list', ["articles" => $articles, "count" => $count]); + } + + public function show( $id ) { + $articles = Article::where('id', $id); + $articles = $articles->simplePaginate(10); + $page_title = ""; + foreach($articles as $a) { + $page_title = $a->title; + } + return view('list', ["articles" => $articles, "count" => 1, "page_title" => $page_title]); + } + + public function search(Request $request) { + $search_unsafe = $request->input("q"); + + if ( "" == $search_unsafe ) { + $search_unsafe = ""; + } + + $search_unsafe = explode(",", $request->input("q")); + + $articles = new Article; + + if ( "on" == $request->input("onlypopular") ) { + $articles = $articles->setTable('view_popular'); + } + + foreach($search_unsafe as $q) { + $q = Helper::escapeLike($q); + $q = "%".$q."%"; + $articles = $articles->where(function ($query) use ($q) { + $query->whereHas('getCategories', function ($query) use ($q){ + $query->where('name', 'like', $q); + }) + ->orWhere('title', 'like', $q) + ->orWhere('excerpt_html', 'like', $q); + }); + } + $count = $articles->count(); + + if ( "on" == $request->input("onlypopular") ) { + $articles = $articles->orderBy('impact', 'desc'); + } + $articles = $articles->orderBy('created_at', 'desc'); + $articles = $articles->simplePaginate(10); + + return view('list', ["articles" => $articles, "count" => $count]); + } + + public function popular() + { + $articles = new Article; + $articles = $articles->setTable('view_popular'); + $count = $articles->count(); + $articles = $articles->simplePaginate(10); + + return view('list', ["articles" => $articles, "count" => $count]); + } + + function topicindex() { + $categories = Category::orderBy('name'); + $letters = DB::select("SELECT DISTINCT LEFT(name, 1) as name FROM category ORDER BY left(name, 1);"); + + return view('topicindex', ['topics' => $categories, 'letters' => $letters]); + } + + public function random() { + $articles = new Article; + $articles = $articles->inRandomOrder(); + $count = $articles->count(); + $articles = $articles->simplePaginate(10); + + return view('list', ["articles" => $articles, "count" => $count]); + } + + public function populartopics() { + $topics = DB::select(" + SELECT + c.name, + count(c.name) AS count + FROM category AS c + JOIN + article_category AS ac ON c.id = ac.category_id + GROUP BY + c.name + ORDER BY count(c.name) DESC;"); +#echo "<pre>"; var_dump($topics);exit; + + return view('topicpopular', ['topics' => $topics ]); + } +} diff --git a/ssh/app/Http/Kernel.php b/ssh/app/Http/Kernel.php new file mode 100644 index 0000000..09ccbc9 --- /dev/null +++ b/ssh/app/Http/Kernel.php @@ -0,0 +1,66 @@ +<?php + +namespace App\Http; + +use Illuminate\Foundation\Http\Kernel as HttpKernel; + +class Kernel extends HttpKernel +{ + /** + * The application's global HTTP middleware stack. + * + * These middleware are run during every request to your application. + * + * @var array + */ + protected $middleware = [ + \App\Http\Middleware\TrustProxies::class, + \Illuminate\Http\Middleware\HandleCors::class, + \App\Http\Middleware\CheckForMaintenanceMode::class, + \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, + \App\Http\Middleware\TrimStrings::class, + \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, + ]; + + /** + * The application's route middleware groups. + * + * @var array + */ + protected $middlewareGroups = [ + 'web' => [ + \App\Http\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + // \Illuminate\Session\Middleware\AuthenticateSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \App\Http\Middleware\VerifyCsrfToken::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + + 'api' => [ + 'throttle:60,1', + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + ]; + + /** + * The application's route middleware. + * + * These middleware may be assigned to groups or used individually. + * + * @var array + */ + protected $routeMiddleware = [ + 'auth' => \App\Http\Middleware\Authenticate::class, + 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, + 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, + 'can' => \Illuminate\Auth\Middleware\Authorize::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, + 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, + ]; +} diff --git a/ssh/app/Http/Middleware/Authenticate.php b/ssh/app/Http/Middleware/Authenticate.php new file mode 100644 index 0000000..704089a --- /dev/null +++ b/ssh/app/Http/Middleware/Authenticate.php @@ -0,0 +1,21 @@ +<?php + +namespace App\Http\Middleware; + +use Illuminate\Auth\Middleware\Authenticate as Middleware; + +class Authenticate extends Middleware +{ + /** + * Get the path the user should be redirected to when they are not authenticated. + * + * @param \Illuminate\Http\Request $request + * @return string|null + */ + protected function redirectTo($request) + { + if (! $request->expectsJson()) { + return route('login'); + } + } +} diff --git a/ssh/app/Http/Middleware/CheckForMaintenanceMode.php b/ssh/app/Http/Middleware/CheckForMaintenanceMode.php new file mode 100644 index 0000000..35b9824 --- /dev/null +++ b/ssh/app/Http/Middleware/CheckForMaintenanceMode.php @@ -0,0 +1,17 @@ +<?php + +namespace App\Http\Middleware; + +use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware; + +class CheckForMaintenanceMode extends Middleware +{ + /** + * The URIs that should be reachable while maintenance mode is enabled. + * + * @var array + */ + protected $except = [ + // + ]; +} diff --git a/ssh/app/Http/Middleware/EncryptCookies.php b/ssh/app/Http/Middleware/EncryptCookies.php new file mode 100644 index 0000000..033136a --- /dev/null +++ b/ssh/app/Http/Middleware/EncryptCookies.php @@ -0,0 +1,17 @@ +<?php + +namespace App\Http\Middleware; + +use Illuminate\Cookie\Middleware\EncryptCookies as Middleware; + +class EncryptCookies extends Middleware +{ + /** + * The names of the cookies that should not be encrypted. + * + * @var array + */ + protected $except = [ + // + ]; +} diff --git a/ssh/app/Http/Middleware/RedirectIfAuthenticated.php b/ssh/app/Http/Middleware/RedirectIfAuthenticated.php new file mode 100644 index 0000000..2395ddc --- /dev/null +++ b/ssh/app/Http/Middleware/RedirectIfAuthenticated.php @@ -0,0 +1,27 @@ +<?php + +namespace App\Http\Middleware; + +use App\Providers\RouteServiceProvider; +use Closure; +use Illuminate\Support\Facades\Auth; + +class RedirectIfAuthenticated +{ + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string|null $guard + * @return mixed + */ + public function handle($request, Closure $next, $guard = null) + { + if (Auth::guard($guard)->check()) { + return redirect(RouteServiceProvider::HOME); + } + + return $next($request); + } +} diff --git a/ssh/app/Http/Middleware/TrimStrings.php b/ssh/app/Http/Middleware/TrimStrings.php new file mode 100644 index 0000000..5a50e7b --- /dev/null +++ b/ssh/app/Http/Middleware/TrimStrings.php @@ -0,0 +1,18 @@ +<?php + +namespace App\Http\Middleware; + +use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware; + +class TrimStrings extends Middleware +{ + /** + * The names of the attributes that should not be trimmed. + * + * @var array + */ + protected $except = [ + 'password', + 'password_confirmation', + ]; +} diff --git a/ssh/app/Http/Middleware/TrustProxies.php b/ssh/app/Http/Middleware/TrustProxies.php new file mode 100644 index 0000000..3e347db --- /dev/null +++ b/ssh/app/Http/Middleware/TrustProxies.php @@ -0,0 +1,29 @@ +<?php + +namespace App\Http\Middleware; + +#use Fideloper\Proxy\TrustProxies as Middleware; +use Illuminate\Http\Middleware\TrustProxies as Middleware; +use Illuminate\Http\Request; + +class TrustProxies extends Middleware +{ + /** + * The trusted proxies for this application. + * + * @var array|string + */ + protected $proxies = [ '192.168.122.1' ]; + + /** + * The headers that should be used to detect proxies. + * + * @var int + */ + protected $headers = + Request::HEADER_X_FORWARDED_FOR | + Request::HEADER_X_FORWARDED_HOST | + Request::HEADER_X_FORWARDED_PORT | + Request::HEADER_X_FORWARDED_PROTO | + Request::HEADER_X_FORWARDED_AWS_ELB; +} diff --git a/ssh/app/Http/Middleware/VerifyCsrfToken.php b/ssh/app/Http/Middleware/VerifyCsrfToken.php new file mode 100644 index 0000000..0c13b85 --- /dev/null +++ b/ssh/app/Http/Middleware/VerifyCsrfToken.php @@ -0,0 +1,17 @@ +<?php + +namespace App\Http\Middleware; + +use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; + +class VerifyCsrfToken extends Middleware +{ + /** + * The URIs that should be excluded from CSRF verification. + * + * @var array + */ + protected $except = [ + // + ]; +} diff --git a/ssh/app/Libraries/Helper.php b/ssh/app/Libraries/Helper.php new file mode 100644 index 0000000..5029a1c --- /dev/null +++ b/ssh/app/Libraries/Helper.php @@ -0,0 +1,303 @@ +<?php +namespace App\Libraries; +use App\Libraries\Helper; +use Carbon\Carbon; +use Rumenx\Feed\FeedFactory; + +class Helper { + public static function escapeLike($string){ + $search = array('%', '_'); + $replace = array('\%', '\_'); + $string = str_replace($search, $replace, $string); + $string = explode(" ", $string); + return implode("%", $string); + } + + public static function formatTimestamp($timestamp) { + return Carbon::createFromTimestamp($timestamp)->format("Y-m-d"); + } + + public static function makeFeed($model, $title, $cache = 60) { + + switch($title) { + case("new"): + $feed_title = 'Newest Articles'; + $feed_description = 'Newest interesting articles from Wikipedia. Keep exploring.'; + break; + case( "popular"): + $feed_title = 'Popular Articles'; + $feed_description = 'The most popular articles. Keep exploring.'; + break; + case( "mastodon"): + $feed_title = 'Feed for Mastodon'; + $feed_description = 'New articles are published automatically to Mastodon.'; + break; + default: + $feed_title = 'Search for: ' . $title; + $feed_description = 'All articles for "' . $title . '".'; + break; + } + $feed_title .= " | mostdiscussed.com"; + + // create new feed + $feed = FeedFactory::create(); + + // multiple feeds are supported + // if you are using caching you should set different cache keys for your feeds + + // cache the feed for $cache minutes (second parameter is optional) + $feed->setCache($cache, 'feed_' . $title); + + // check if there is cached feed and build new only if is not + if (!$feed->isCached()) + { + + // set your feed's title, description, link, pubdate and language + $feed->setTitle($feed_title); + $feed->setDescription($feed_description); + $feed->setSubtitle($feed_description); + #$feed->setLogo('http://yoursite.tld/logo.jpg'); + $feed->setLink(url('feed/' . $title)); + $feed->setDateFormat('datetime'); // 'datetime', 'timestamp' or 'carbon' + $feed->setPubdate($model[0]->created_at); + $feed->setLang('en'); + $feed->setShortening(false); // true or false + + if ( "mastodon" == $title || "mastodon_test" == $title ) { + $feed->setTextLimit(500); // maximum length of description text + } else { + $feed->setTextLimit(100); // maximum length of description text + } + + foreach ($model as $post) + { + + $desc = ($post->excerpt_html); + $categories = null; + + if ( "mastodon" == $title || "mastodon_test" == $title ) { + + $cat_len= 0; + + if ( ! $post->getCategories()->get()->isEmpty() ) { + + $categories_ar = array("#MostDiscussed"); + + foreach( $post->getCategories()->get() as $cat ) { + + // uppercase for every word in a possible multi worded hashtag + $tmp_cat = ucwords($cat->name); + + // strip everything after / for brevity + if ( false !== strpos($tmp_cat, "/") ) + $tmp_cat = substr($tmp_cat, 0, strpos($tmp_cat, "/")); + + // replace any non-alphanumeric character except underscore, because + // it's not allowed to be used in a hashtag + $tmp_cat = preg_replace("/[^A-Za-z0-9_]/", '', $tmp_cat); + + // trim just in case + $tmp_cat = trim($tmp_cat); + + // if it's not empty, add it to the hashtag array + if ( "" != $tmp_cat ) + $categories_ar[] = "#". $tmp_cat; + } + + // remove possible duplicates (because stripping after "/") + $categories_ar = array_unique($categories_ar); + + // join to one string + $categories = implode(" ", $categories_ar); + + $cat_counter = $post->getCategories()->get()->count(); + $cat_len = mb_strlen($categories, "UTF-8"); + } + + $link = env('APP_URL') . "/article/" . $post->id; + + // max desc length is 500 - 23 (Link) - $cat_len - 2 (white spaces) + $max_len = 500 - 23 - $cat_len - 2; + + if ( "mastodon_test" == $title ) { + $desc = Helper::mastodon_summary($desc, $max_len); + }else { + $desc = Helper::first_sentence($desc, $max_len); + #$desc = Helper::mastodon_summary($desc, $max_len); + } + + $desc .= " " . $categories;# . $discussions; + + // set item's title, author, url, pubdate, description, content, enclosure (optional)* + $feed->addItem([ + 'title' => $desc, // mastofeed.org seems to ignore the description field + 'author' => env('APP_NAME'), + 'url' => $link, + 'link' => $link, + 'pubdate' => $post->created_at, + 'description' => $desc, + 'content' => $desc + ]); + + } else { + if ( ! $post->getCategories()->get()->isEmpty() ) { + $categories = "<br>"; + foreach( $post->getCategories()->get() as $cat ) { + $categories .= "<a href='". \URL::to('/topic/' . $cat->name) ."'>". $cat->name . "</a> | "; + } + $categories = rtrim($categories, " | "); + $desc .= "<br>Topics:"; + $desc .= $categories; + } + + $discussions = "<br>"; + foreach( $post->getDiscussions()->orderBy('comments', 'desc')->get() as $dis ) { + $discussions .= "<a href='" . $dis->source_url . "'>" . $dis->title . "</a> | "; + $discussions .= Helper::formatTimestamp($dis->posted_on) . " | " . $dis->upvotes . " Upvotes | " . $dis->comments . " Comments<br>"; + } + $desc .= "<br><br>Discussions:"; + $desc .= $discussions; + + // set item's title, author, url, pubdate, description, content, enclosure (optional)* + $feed->addItem([ + 'title' => $post->title, + 'author' => env('APP_NAME'), + 'url' => \URL::to($post->url), + 'link' => \URL::to($post->url), + 'pubdate' => $post->created_at, + 'description' => $desc, + 'content' => $desc + ]); + } + } + + } + + // first param is the feed format + // optional: second param is cache duration (value of 0 turns off caching) + // optional: you can set custom cache key with 3rd param as string + $xml = $feed->render('atom', $cache, 'feed_' . $title); + return response($xml, 200, [ + 'Content-Type' => 'application/xml' + ]); + } + + public static function first_sentence($content, $max_len = NULL) { + + $content = html_entity_decode(strip_tags($content)); + $content = ltrim($content); + $pos = strpos($content, '.'); + + if($pos === false) { + if ( is_null($max_len) ) { + return $content; + } else { + return substr($content, 0, $max_len); + } + } + else { + return substr($content, 0, $pos+1); + } + + } + + private static function next_sentence($content, $max_len = NULL) { + + $content = ltrim($content); + $pos = strpos($content, '.'); + + if($pos === false) { + if ( is_null($max_len) ) { + return $content; + } else { + return substr($content, 0, $max_len); + } + } else { + return substr($content, 0, $pos+1); + } + + } + + /** + * Make sure to toot as much text as possible while still staying below the limit of 500 chars -link (23 chars) - 2 (white spaces) - possible hashtags + */ + public static function mastodon_summary($excerpt, $max_len = 475){ + + /** + * Strip HTML from Wikipedia excerpt + */ + $excerpt = ltrim(html_entity_decode(strip_tags($excerpt))); + + /** + * The toot to be returned + */ + $content = ""; + + /** + * https://stackoverflow.com/questions/16377437/split-a-text-into-sentences + */ + $sentences = preg_split('/(?<=[.?!])\s+(?=[a-z])/i', $excerpt); + echo "<pre>"; + echo "-----------------------"; + var_dump($excerpt); + var_dump($sentences); + + for ( $i = 0; $i < count($sentences); $i++ ) { + #if ( mb_strlen($content) < $max_len && (mb_strlen($content) + mb_strlen($sentences) ) { + if ( mb_strlen($content) < $max_len && (mb_strlen($content) + mb_strlen($sentences) ) < $max_len ){ + + //var_dump(rtrim(ltrim($sentences[$i]))); + $content .= rtrim(ltrim($sentences[$i])); + var_dump("ok", $max_len); + + $max_len = $max_len - mb_strlen($sentences[$i]); + var_dump("ok", $max_len); + + } else { + var_dump("fail", mb_strlen($content), $max_len); + break; + } + } + return $content; + + echo "<pre>"; + while ( mb_strlen($content) < $max_len ) { + + /** + * Get next sentence + */ + $next_sentence = Helper::next_sentence($excerpt, $max_len); + var_dump($next_sentence); + + if ( "" == $next_sentence ) { + break; + } + + /** + * Check if $content + $next_sentence is still under $max_len + */ + if ( (mb_strlen($content) + mb_strlen($next_sentence)) < $max_len ) { + + /** + * add text + */ + $content .= $next_sentence; + + /** + * Recalc $max_len + */ + $max_len = $max_len - mb_strlen($next_sentence); + + /** + * Remove sentence from excerpt + */ + $excerpt = substr($excerpt, mb_strlen($next_sentence)); + + } else { + break; + } + } + + return $content; + } +} diff --git a/ssh/app/Providers/AppServiceProvider.php b/ssh/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..141751a --- /dev/null +++ b/ssh/app/Providers/AppServiceProvider.php @@ -0,0 +1,29 @@ +<?php + +namespace App\Providers; + +use Illuminate\Support\ServiceProvider; +use Illuminate\Pagination\Paginator; + +class AppServiceProvider extends ServiceProvider +{ + /** + * Register any application services. + * + * @return void + */ + public function register() + { + // + } + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + Paginator::useBootstrap(); + } +} diff --git a/ssh/app/Providers/AuthServiceProvider.php b/ssh/app/Providers/AuthServiceProvider.php new file mode 100644 index 0000000..3049068 --- /dev/null +++ b/ssh/app/Providers/AuthServiceProvider.php @@ -0,0 +1,30 @@ +<?php + +namespace App\Providers; + +use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; +use Illuminate\Support\Facades\Gate; + +class AuthServiceProvider extends ServiceProvider +{ + /** + * The policy mappings for the application. + * + * @var array + */ + protected $policies = [ + // 'App\Model' => 'App\Policies\ModelPolicy', + ]; + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + // + } +} diff --git a/ssh/app/Providers/BroadcastServiceProvider.php b/ssh/app/Providers/BroadcastServiceProvider.php new file mode 100644 index 0000000..395c518 --- /dev/null +++ b/ssh/app/Providers/BroadcastServiceProvider.php @@ -0,0 +1,21 @@ +<?php + +namespace App\Providers; + +use Illuminate\Support\Facades\Broadcast; +use Illuminate\Support\ServiceProvider; + +class BroadcastServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + Broadcast::routes(); + + require base_path('routes/channels.php'); + } +} diff --git a/ssh/app/Providers/EventServiceProvider.php b/ssh/app/Providers/EventServiceProvider.php new file mode 100644 index 0000000..723a290 --- /dev/null +++ b/ssh/app/Providers/EventServiceProvider.php @@ -0,0 +1,34 @@ +<?php + +namespace App\Providers; + +use Illuminate\Auth\Events\Registered; +use Illuminate\Auth\Listeners\SendEmailVerificationNotification; +use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; +use Illuminate\Support\Facades\Event; + +class EventServiceProvider extends ServiceProvider +{ + /** + * The event listener mappings for the application. + * + * @var array + */ + protected $listen = [ + Registered::class => [ + SendEmailVerificationNotification::class, + ], + ]; + + /** + * Register any events for your application. + * + * @return void + */ + public function boot() + { + parent::boot(); + + // + } +} diff --git a/ssh/app/Providers/RouteServiceProvider.php b/ssh/app/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..527eee3 --- /dev/null +++ b/ssh/app/Providers/RouteServiceProvider.php @@ -0,0 +1,80 @@ +<?php + +namespace App\Providers; + +use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; +use Illuminate\Support\Facades\Route; + +class RouteServiceProvider extends ServiceProvider +{ + /** + * This namespace is applied to your controller routes. + * + * In addition, it is set as the URL generator's root namespace. + * + * @var string + */ + protected $namespace = 'App\Http\Controllers'; + + /** + * The path to the "home" route for your application. + * + * @var string + */ + public const HOME = '/home'; + + /** + * Define your route model bindings, pattern filters, etc. + * + * @return void + */ + public function boot() + { + // + + parent::boot(); + } + + /** + * Define the routes for the application. + * + * @return void + */ + public function map() + { + $this->mapApiRoutes(); + + $this->mapWebRoutes(); + + // + } + + /** + * Define the "web" routes for the application. + * + * These routes all receive session state, CSRF protection, etc. + * + * @return void + */ + protected function mapWebRoutes() + { + Route::middleware('web') + ->namespace($this->namespace) + ->group(base_path('routes/web.php')); + } + + /** + * Define the "api" routes for the application. + * + * These routes are typically stateless. + * + * @return void + */ + protected function mapApiRoutes() + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->namespace) + ->group(base_path('routes/api.php')); + } +} diff --git a/ssh/app/User.php b/ssh/app/User.php new file mode 100644 index 0000000..e79dab7 --- /dev/null +++ b/ssh/app/User.php @@ -0,0 +1,39 @@ +<?php + +namespace App; + +use Illuminate\Contracts\Auth\MustVerifyEmail; +use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Notifications\Notifiable; + +class User extends Authenticatable +{ + use Notifiable; + + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'name', 'email', 'password', + ]; + + /** + * The attributes that should be hidden for arrays. + * + * @var array + */ + protected $hidden = [ + 'password', 'remember_token', + ]; + + /** + * The attributes that should be cast to native types. + * + * @var array + */ + protected $casts = [ + 'email_verified_at' => 'datetime', + ]; +} |
