forked from miguel456/rbrecruiter
Made Profile & Account Settings functional
Also moved redundant HTML markup to component file for reuse. Username to UUID converter also added as Middleware
This commit is contained in:
parent
7635f8e2f4
commit
2ff0da3e4f
|
@ -3,11 +3,13 @@
|
|||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Profile;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use function GuzzleHttp\Psr7\str;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
|
@ -50,6 +52,7 @@ class RegisterController extends Controller
|
|||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'uuid' => ['required', 'string', 'unique:users', 'min:32', 'max:32'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
||||
|
@ -64,11 +67,24 @@ class RegisterController extends Controller
|
|||
*/
|
||||
protected function create(array $data)
|
||||
{
|
||||
return User::create([
|
||||
|
||||
$user = User::create([
|
||||
'uuid' => $data['uuid'],
|
||||
'name' => $data['name'],
|
||||
'email' => $data['email'],
|
||||
'password' => Hash::make($data['password']),
|
||||
'originalIP' => request()->ip()
|
||||
]);
|
||||
|
||||
Profile::create([
|
||||
|
||||
'profileShortBio' => 'Write a one-liner about you here!',
|
||||
'profileAboutMe' => 'Tell us a bit about you.',
|
||||
'socialLinks' => '{}',
|
||||
'userID' => $user->id
|
||||
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class LogController extends Controller
|
||||
{
|
||||
//
|
||||
}
|
|
@ -2,15 +2,81 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ProfileSave;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Profile;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
public function showProfile()
|
||||
{
|
||||
|
||||
return view('dashboard.user.profile.userprofile');
|
||||
$socialMediaProfiles = json_decode(Auth::user()->profile->socialLinks, true);
|
||||
|
||||
return view('dashboard.user.profile.userprofile')
|
||||
->with([
|
||||
'profile' => Auth::user()->profile,
|
||||
'github' => $socialMediaProfiles['links']['github'] ?? 'UpdateMe',
|
||||
'twitter' => $socialMediaProfiles['links']['twitter'] ?? 'UpdateMe',
|
||||
'insta' => $socialMediaProfiles['links']['insta'] ?? 'UpdateMe',
|
||||
'discord' => $socialMediaProfiles['links']['discord'] ?? 'UpdateMe#12345',
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function saveProfile(ProfileSave $request)
|
||||
{
|
||||
// TODO: Implement profile security policy for logged in users
|
||||
|
||||
$profile = Profile::find(Auth::user()->id);
|
||||
$social = [];
|
||||
|
||||
if (!is_null($profile))
|
||||
{
|
||||
switch ($request->avatarPref)
|
||||
{
|
||||
case 'MOJANG':
|
||||
$avatarPref = 'crafatar';
|
||||
|
||||
break;
|
||||
case 'GRAVATAR':
|
||||
$avatarPref = strtolower($request->avatarPref);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$social['links']['github'] = $request->socialGithub;
|
||||
$social['links']['twitter'] = $request->socialTwitter;
|
||||
$social['links']['insta'] = $request->socialInsta;
|
||||
$social['links']['discord'] = $request->socialDiscord;
|
||||
|
||||
$profile->profileShortBio = $request->shortBio;
|
||||
$profile->profileAboutMe = $request->aboutMe;
|
||||
$profile->avatarPreference = $avatarPref;
|
||||
$profile->socialLinks = json_encode($social);
|
||||
|
||||
$profile->save();
|
||||
|
||||
$request->session()->flash('success', 'Profile settings saved successfully.');
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$gm = 'Guru Meditation #' . rand(0, 1000);
|
||||
Log::alert('[GURU MEDITATION]: Could not find profile for authenticated user ' . Auth::user()->name . 'whilst trying to update it! Please verify that profiles are being created automatically during signup.',
|
||||
[
|
||||
'uuid' => Auth::user()->uuid,
|
||||
'timestamp' => now(),
|
||||
'route' => $request->route()->getName(),
|
||||
'gmcode' => $gm // If this error is reported, the GM code, denoting a severe error, will help us find this entry in the logs
|
||||
|
||||
]);
|
||||
$request->session()->flash('error', 'A technical error has occurred whilst trying to save your profile. Incident details have been recorded. Please report this incident to administrators with the following case number: ' . $gm);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ChangeEmailRequest;
|
||||
use App\Http\Requests\ChangePasswordRequest;
|
||||
use App\Http\Requests\FlushSessionsRequest;
|
||||
use App\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
|
@ -16,4 +23,76 @@ class UserController extends Controller
|
|||
{
|
||||
return view('dashboard.administration.players');
|
||||
}
|
||||
|
||||
public function showAccount()
|
||||
{
|
||||
return view('dashboard.user.profile.useraccount')
|
||||
->with('ip', request()->ip());
|
||||
}
|
||||
|
||||
|
||||
public function flushSessions(FlushSessionsRequest $request)
|
||||
{
|
||||
// TODO: Move all log calls to a listener, which binds to an event fired by each significant event, such as this one
|
||||
// This will allow for other actions to be performed on certain events (like login failed event)
|
||||
|
||||
Auth::logoutOtherDevices($request->currentPasswordFlush);
|
||||
Log::notice('User ' . Auth::user()->name . ' has logged out other devices in their account',
|
||||
[
|
||||
'originIPAddress' => $request->ip(),
|
||||
'userID' => Auth::user()->id,
|
||||
'timestamp' => now()
|
||||
]);
|
||||
|
||||
$request->session()->flash('success', 'Successfully logged out other devices. Remember to change your password if you think you\'ve been compromised.');
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function changePassword(ChangePasswordRequest $request)
|
||||
{
|
||||
$user = User::find(Auth::user()->id);
|
||||
|
||||
if (!is_null($user))
|
||||
{
|
||||
$user->password = Hash::make($request->newPassword);
|
||||
$user->save();
|
||||
|
||||
Log::info('User ' . $user->name . ' has changed their password', [
|
||||
'originIPAddress' => $request->ip(),
|
||||
'userID' => $user->id,
|
||||
'timestamp' => now()
|
||||
]);
|
||||
Auth::logout();
|
||||
|
||||
// After logout, the user gets caught by the auth filter, and it automatically redirects back to the previous page
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function changeEmail(ChangeEmailRequest $request)
|
||||
{
|
||||
$user = User::find(Auth::user()->id);
|
||||
|
||||
if (!is_null($user))
|
||||
{
|
||||
$user->email = $request->newEmail;
|
||||
$user->save();
|
||||
|
||||
Log::notice('User ' . $user->name . ' has just changed their contact email address', [
|
||||
'originIPAddress' => $request->ip(),
|
||||
'userID' => $user->id,
|
||||
'timestamp' => now()
|
||||
]);
|
||||
|
||||
$request->session()->flash('success', 'Your email address has been changed!');
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('error', 'There has been an error whilst trying to update your account. Please contact administrators.');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class Kernel extends HttpKernel
|
|||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'eligibility' => \App\Http\Middleware\ApplicationEligibility::class
|
||||
'eligibility' => \App\Http\Middleware\ApplicationEligibility::class,
|
||||
'usernameUUID' => \App\Http\Middleware\UsernameUUID::class
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class UsernameUUID
|
||||
{
|
||||
/**
|
||||
* Converts a Minecraft username found in the request body to a UUID
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$input = $request->all();
|
||||
if (isset($input['uuid']))
|
||||
{
|
||||
// TODO: Switch to custom Facade
|
||||
$username = $input['uuid'];
|
||||
|
||||
$conversionRequest = Http::get(config('general.urls.mojang.api') . '/users/profiles/minecraft/' . $username)->body();
|
||||
$decodedConversionRequest = json_decode($conversionRequest, true);
|
||||
|
||||
$input['uuid'] = $decodedConversionRequest['id'];
|
||||
|
||||
$request->replace($input);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChangeEmailRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'currentPassword' => 'required|password',
|
||||
'newEmail' => 'required|email|unique:users,email'
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChangePasswordRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'newPassword' => 'required|string|confirmed',
|
||||
'oldPassword' => 'required|string|password'
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FlushSessionsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'currentPasswordFlush' => 'required|password'
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Profile;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ProfileSave extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @param Profile $profile
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(Profile $profile)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'shortBio' => 'nullable|string|max:100',
|
||||
'aboutMe' => 'nullable|string|max:2000',
|
||||
'avatarPref' => 'required|string',
|
||||
'socialInsta' => 'nullable|string',
|
||||
'socialTwitter' => 'nullable|string',
|
||||
'socialDiscord' => 'nullable|string',
|
||||
'socialGithub' => 'nullable|string'
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class OnUserRegistration
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param Registered $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Registered $event)
|
||||
{
|
||||
// TODO: Send push notification to online admins via browser (w/ pusher)
|
||||
Log::info('User ' . $event->user->name . ' has just registered for an account.');
|
||||
}
|
||||
}
|
10
app/Log.php
10
app/Log.php
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Log extends Model
|
||||
{
|
||||
//
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ProfilePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Create a new policy instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -6,5 +6,20 @@ use Illuminate\Database\Eloquent\Model;
|
|||
|
||||
class Profile extends Model
|
||||
{
|
||||
//
|
||||
|
||||
public $fillable = [
|
||||
|
||||
'profileShortBio',
|
||||
'profileAboutMe',
|
||||
'avatarPreference',
|
||||
'socialLinks',
|
||||
'userID'
|
||||
|
||||
];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User', 'userID', 'id');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Listeners\OnUserRegistration;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
@ -17,6 +18,7 @@ class EventServiceProvider extends ServiceProvider
|
|||
protected $listen = [
|
||||
Registered::class => [
|
||||
SendEmailVerificationNotification::class,
|
||||
OnUserRegistration::class
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class MojangStatusProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
|
||||
// TODO: (IMPORTANT) Switch this to Middleware
|
||||
if (!Cache::has('mojang_status'))
|
||||
{
|
||||
Log::info("Mojang Status Provider: Mojang Status not found in the cache; Sending new request.");
|
||||
|
|
|
@ -41,4 +41,9 @@ class User extends Authenticatable
|
|||
{
|
||||
return $this->hasMany('App\Application', 'applicantUserID', 'id');
|
||||
}
|
||||
|
||||
public function profile()
|
||||
{
|
||||
return $this->hasOne('App\Profile', 'userID', 'id');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class GlobalErrors extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*
|
||||
* @return \Illuminate\View\View|string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
return view('components.global-errors');
|
||||
}
|
||||
}
|
|
@ -208,7 +208,7 @@ return [
|
|||
*/
|
||||
|
||||
'menu' => [
|
||||
'My Account',
|
||||
'Applications',
|
||||
[
|
||||
'text' => 'My Applications',
|
||||
'icon' => 'fas fa-fw fa-list-ul',
|
||||
|
@ -218,7 +218,7 @@ return [
|
|||
'icon' => 'fas fa-fw fa-check-double',
|
||||
'url' => '/applications/current'
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
],
|
||||
'My Profile',
|
||||
|
@ -227,6 +227,11 @@ return [
|
|||
'url' => '/profile/settings',
|
||||
'icon' => 'fas fa-fw fa-cog'
|
||||
],
|
||||
[
|
||||
'text' => 'My Account Settings',
|
||||
'icon' => 'fas fa-user-circle',
|
||||
'url' => '/profile/settings/account'
|
||||
],
|
||||
'Application Management',
|
||||
[
|
||||
'text' => 'Outstanding Applications',
|
||||
|
|
|
@ -7,7 +7,8 @@ return [
|
|||
|
||||
'mojang' => [
|
||||
|
||||
'statuscheck' => env('MOJANG_STATUS_URL') ?? 'https://status.mojang.com/check'
|
||||
'statuscheck' => env('MOJANG_STATUS_URL') ?? 'https://status.mojang.com/check',
|
||||
'api' => env('MOJANG_API_URL') ?? ' https://api.mojang.com'
|
||||
|
||||
]
|
||||
]
|
||||
|
|
|
@ -15,17 +15,20 @@ class CreateProfilesTable extends Migration
|
|||
{
|
||||
Schema::create('profiles', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('profileShortBio');
|
||||
$table->text('profileAboutMe');
|
||||
$table->string('profileShortBio')->nullable();
|
||||
$table->text('profileAboutMe')->nullable();
|
||||
$table->enum('avatarPreference', [
|
||||
'crafatar', // Mojang Profile
|
||||
'gravatar' // Email profile
|
||||
]);
|
||||
$table->text('socialLinks');
|
||||
])->default('gravatar');
|
||||
$table->text('socialLinks')->nullable();
|
||||
$table->bigInteger('userID')->unsigned();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('userID')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->foreign('userID')
|
||||
->references('id')
|
||||
->on('users')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class CreateVacanciesTable extends Migration
|
|||
$table->longText('vacancyDescription');
|
||||
$table->string('permissionGroupName');
|
||||
$table->string('discordRoleID');
|
||||
$table->bigInteger('vacancyFormID')->unsigned();
|
||||
$table->unsignedBigInteger('vacancyFormID');
|
||||
$table->integer('vacancyCount')->default(3);
|
||||
$table->timestamps();
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
.card {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid rgba(0, 34, 51, 0.1);
|
||||
box-shadow: 2px 4px 10px 0 rgba(0, 34, 51, 0.05), 2px 4px 10px 0 rgba(0, 34, 51, 0.05);
|
||||
border-radius: 0.15rem;
|
||||
}
|
||||
|
||||
/* Tabs Card */
|
||||
|
||||
.tab-card {
|
||||
border:1px solid #eee;
|
||||
}
|
||||
|
||||
.tab-card-header {
|
||||
background:none;
|
||||
}
|
||||
/* Default mode */
|
||||
.tab-card-header > .nav-tabs {
|
||||
border: none;
|
||||
margin: 0px;
|
||||
}
|
||||
.tab-card-header > .nav-tabs > li {
|
||||
margin-right: 2px;
|
||||
}
|
||||
.tab-card-header > .nav-tabs > li > a {
|
||||
border: 0;
|
||||
border-bottom:2px solid transparent;
|
||||
margin-right: 0;
|
||||
color: #737373;
|
||||
padding: 2px 15px;
|
||||
}
|
||||
|
||||
.tab-card-header > .nav-tabs > li > a.show {
|
||||
border-bottom:2px solid #007bff;
|
||||
color: #007bff;
|
||||
}
|
||||
.tab-card-header > .nav-tabs > li > a:hover {
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.tab-card-header > .tab-content {
|
||||
padding-bottom: 0;
|
||||
}
|
|
@ -61,6 +61,20 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mt-5">
|
||||
<label for="minecraftUsername" class="col-md-4 col-form-label text-md-right">Minecraft Username</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input type="text" id="minecraftUsername" name="uuid" class="form-control" required>
|
||||
|
||||
@error('uuid')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<!-- I begin to speak only when I am certain what I will say is not better left unsaid - Cato the Younger -->
|
||||
|
||||
@if (session()->has('success'))
|
||||
|
||||
<script>
|
||||
toastr.success("{{session('success')}}")
|
||||
</script>
|
||||
|
||||
@elseif(session()->has('error'))
|
||||
|
||||
<script>
|
||||
toastr.error("{{session('error')}}")
|
||||
</script>
|
||||
|
||||
@elseif($errors->any())
|
||||
|
||||
@foreach($errors->all() as $error)
|
||||
<script>
|
||||
toastr.error('{{$error}}')
|
||||
</script>
|
||||
@endforeach
|
||||
|
||||
@endif
|
|
@ -10,20 +10,7 @@
|
|||
|
||||
@section('js')
|
||||
|
||||
@if (session()->has('success'))
|
||||
|
||||
<script>
|
||||
toastr.success("{{session('success')}}")
|
||||
</script>
|
||||
|
||||
@elseif(session()->has('error'))
|
||||
|
||||
<script>
|
||||
toastr.error("{{session('error')}}")
|
||||
</script>
|
||||
|
||||
|
||||
@endif
|
||||
<x-global-errors></x-global-errors>
|
||||
|
||||
@stop
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
<!-- /.card-header -->
|
||||
<div class="card-body p-0"> <!-- move to dedi css -->
|
||||
|
||||
@if (!$applications->isEmpty())
|
||||
|
||||
<table class="table" style="white-space: nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -128,6 +130,14 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
@else
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<p><i class="fa fa-info-circle"></i> <b>Nothing to show</b></p>
|
||||
<p>You currently have no applications to display. If you're eligible, you may apply once every month.</p>
|
||||
</div>
|
||||
|
||||
@endif
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
@extends('adminlte::page')
|
||||
|
||||
@section('title', 'Raspberry Network | Applications')
|
||||
|
||||
@section('content_header')
|
||||
|
||||
<h4>My Account / Approved Applications</h4>
|
||||
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<div class="callout callout-success">
|
||||
<h5>Info on approved applications</h5>
|
||||
|
||||
<p>Your approved applications will appear here. Approved applicants will be promoted and notified automatically by the system.</p>
|
||||
<p>Moderators will be able to review other applications.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">My Denied Applications</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body p-0"> <!-- move to dedi css -->
|
||||
|
||||
<table class="table" style="white-space: nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 10px">#</th>
|
||||
<th>Applicant</th>
|
||||
<th>Application Date</th>
|
||||
<th>Approval Date</th>
|
||||
<th>Status</th>
|
||||
<th style="width: 40px">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1.</td>
|
||||
<td>Jonathan Smith</td>
|
||||
<td>2020-04-28</td>
|
||||
<td>2020-04-30</td>
|
||||
<td><span class="badge bg-success">Approved</span></td>
|
||||
<td>
|
||||
|
||||
<button type="button" class="btn btn-success btn-sm">View</button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
|
||||
<div class="card-footer">
|
||||
|
||||
<button type="button" class="btn btn-default mr-2">Back</button>
|
||||
<button type="button" class="btn btn-info mr-2" onclick="window.location.href='{{route('userDeniedApps')}}'">Denied Applications</button>
|
||||
<button type="button" class="btn btn-info mr-2" onclick="window.location.href='{{route('userPendingApps')}}'">Active Applications</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
|
@ -1,83 +0,0 @@
|
|||
@extends('adminlte::page')
|
||||
|
||||
@section('title', 'Raspberry Network | Applications')
|
||||
|
||||
@section('content_header')
|
||||
|
||||
<h4>My Account / Denied Applications</h4>
|
||||
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<div class="callout callout-danger">
|
||||
<h5>Info on denied applications</h5>
|
||||
|
||||
<p>Please note that all applications listed on this page have been denied by the staff team / applications team.</p>
|
||||
<p>The system will only let you apply every thirty days. Your previous applications will be kept for your reference, but you can always delete them here.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">My Denied Applications</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body p-0"> <!-- move to dedi css -->
|
||||
|
||||
<table class="table" style="white-space: nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 10px">#</th>
|
||||
<th>Applicant</th>
|
||||
<th>Application Date</th>
|
||||
<th>Denial Date</th>
|
||||
<th>Status</th>
|
||||
<th style="width: 40px">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1.</td>
|
||||
<td>Jonathan Smith</td>
|
||||
<td>2020-04-28</td>
|
||||
<td>2020-04-30</td>
|
||||
<td><span class="badge bg-danger">Denied</span></td>
|
||||
<td>
|
||||
|
||||
<button type="button" class="btn btn-success btn-sm">View</button>
|
||||
<button type="button" class="btn btn-danger btn-sm">Delete</button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
|
||||
<div class="card-footer">
|
||||
|
||||
<button type="button" class="btn btn-default mr-2">Back</button>
|
||||
<button type="button" class="btn btn-info mr-2">Approved Applications</button>
|
||||
<button type="button" class="btn btn-info mr-2">Active Applications</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
|
@ -0,0 +1,166 @@
|
|||
@extends('adminlte::page')
|
||||
|
||||
@section('title', 'Raspberry Network | Account Settings')
|
||||
|
||||
@section('content_header')
|
||||
|
||||
<h4>My Profile / Account / Settings</h4>
|
||||
|
||||
@stop
|
||||
|
||||
@section('js')
|
||||
|
||||
<x-global-errors></x-global-errors>
|
||||
|
||||
@stop
|
||||
|
||||
@section('css')
|
||||
<link rel="stylesheet" href="/css/acc.css">
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
<div class="modal fade" tabindex="-1" id="authenticationForm" role="dialog" aria-labelledby="authenticationFormLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="authenticationFormLabel">Please authenticate</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-muted">For your security, you'll need to re-enter your password before logging out other devices. If you believe your account has been compromised, please change your password instead, as that will automatically log out anyone else who might using your account, and prevent them from signing back in.</p>
|
||||
|
||||
<form method="POST" action="{{route('flushSessions')}}" id="flushSessions">
|
||||
@csrf
|
||||
<label for="reenter">Re-enter your password</label>
|
||||
<input type="password" name="currentPasswordFlush" id="currentPasswordFlush" class="form-control" autocomplete="current-password">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" onclick="document.getElementById('flushSessions').submit()">Confirm</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col text-center">
|
||||
|
||||
<div class="card">
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<h3>Welcome back, {{Auth::user()->name}}</h3>
|
||||
|
||||
<p class="text-muted">{{Auth::user()->email}}</p>
|
||||
<a href="https://namemc.com/profile/{{Auth::user()->uuid}}" target="_blank">View @ NameMC</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
<div class="card mt-3 tab-card">
|
||||
<div class="card-header tab-card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs" id="myTab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="accountSecurityTab" data-toggle="tab" href="#accountSecurity" role="tab" aria-controls="AccountSecurity" aria-selected="true">Account Security</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="twofaTab" data-toggle="tab" href="#twofa" role="tab" aria-controls="TwoFa" aria-selected="false">Two Factor Authentication</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="sessionsTab" data-toggle="tab" href="#sessions" role="tab" aria-controls="Sessions" aria-selected="false">Sessions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="contactSettingsTab" data-toggle="tab" href="#contactSettings" role="tab" aria-controls="ContactSettings" aria-selected="false">Contact Settings (E-mail)</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active p-3" id="accountSecurity" role="tabpanel" aria-labelledby="accountSecurityTab">
|
||||
<h5 class="card-title">Change Password</h5>
|
||||
<p class="card-text">Change your password here. This will log you out from all existing sessions for your security.</p>
|
||||
|
||||
<form method="POST" action="{{route('changePassword')}}" id="changePassword">
|
||||
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<label for="oldpassword">Old Password</label>
|
||||
<input class="form-control" name="oldPassword" type="password" id="oldpassword" autocomplete="current-password">
|
||||
<p class="text-sm text-muted">Forgot your password? Reset it <a href="/auth/password/reset">here</a></p>
|
||||
|
||||
<div class="form-group mt-5">
|
||||
|
||||
<label for="newpassword">New Password</label>
|
||||
<input type="password" name="newPassword" id="newpassword" class="form-control" autocomplete="new-password">
|
||||
|
||||
<label for="newpassword_confirmation">Confirm Password</label>
|
||||
<input type="password" name="newPassword_confirmation" id="newpassword_confirmation" autocomplete="new-password" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<button class="btn btn-success" type="button" onclick="document.getElementById('changePassword').submit()">Change Password</button>
|
||||
</div>
|
||||
<div class="tab-pane fade p-3" id="twofa" role="tabpanel" aria-labelledby="twofaTab">
|
||||
<h5 class="card-title">Two-factor Authentication</h5>
|
||||
<p class="card-text"><b>This feature is not yet available.</b> Support for Google Authenticator, Authy, Microsoft Authenticator and other compatible apps is coming soon, as well as fingerprint login for android devices.</p>
|
||||
<button type="button" class="btn btn-primary" disabled>Enable 2FA</button>
|
||||
</div>
|
||||
<div class="tab-pane fade p-3" id="sessions" role="tabpanel" aria-labelledby="sessionsTab">
|
||||
<h5 class="card-title">Session Manager</h5>
|
||||
<p class="card-text">Terminating other sessions is generally a good idea if your account has been compromised.</p>
|
||||
<p>Your current session: Logged in from {{ $ip }}</p>
|
||||
<button type="button" class="btn btn-warning" onclick="$('#authenticationForm').modal('show')">Flush Sessions</button>
|
||||
</div>
|
||||
<div class="tab-pane fade p-3" id="contactSettings" role="tabpanel" aria-labelledby="contactSettingsTab">
|
||||
<h5 class="card-title">Contact Settings</h5>
|
||||
<p class="card-text">Need to change personal data? You can do so here.</p>
|
||||
|
||||
<form method="POST" action="{{route('changeEmail')}}" id="changeEmail">
|
||||
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<div class="form-group">
|
||||
|
||||
<label for="oldEmail">Current Email Address</label>
|
||||
<input type="text" class="form-control" id="oldEmail" disabled value="{{Auth::user()->email}}">
|
||||
|
||||
|
||||
<label for="newEmail">New Email Address</label>
|
||||
<input type="email" name="newEmail" class="form-control mb-3" id="newEmail">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-5">
|
||||
|
||||
<label for="currentPassword">Current Password</label>
|
||||
<input type="password" name="currentPassword" class="form-control" id="currentPassword" autocomplete="current-password">
|
||||
<p class="text-sm text-muted">For security reasons, you cannot make important account changes without confirming your password. You'll also need to verify your new email.</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<button class="btn btn-success" type="button" onclick="document.getElementById('changeEmail').submit()">Change Email Address</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
File diff suppressed because one or more lines are too long
|
@ -12,9 +12,16 @@ use Illuminate\Support\Facades\Route;
|
|||
| contains the "web" middleware group. Now create something great!
|
||||
|
|
||||
*/
|
||||
Auth::routes();
|
||||
|
||||
Route::get('/','HomeController@index')->middleware('eligibility');
|
||||
Route::group(['prefix' => 'auth', 'middleware' => ['usernameUUID']], function (){
|
||||
|
||||
Auth::routes();
|
||||
|
||||
});
|
||||
|
||||
Route::get('/','HomeController@index')
|
||||
->middleware('eligibility');
|
||||
|
||||
Route::post('/form/contact', 'ContactController@create')
|
||||
->name('sendSubmission');
|
||||
|
||||
|
@ -56,7 +63,26 @@ Route::group(['middleware' => 'auth'], function(){
|
|||
|
||||
Route::group(['prefix' => '/profile'], function (){
|
||||
|
||||
Route::get('/settings', 'ProfileController@index');
|
||||
Route::get('/settings', 'ProfileController@showProfile')
|
||||
->name('showProfileSettings');
|
||||
|
||||
Route::patch('/settings/save', 'ProfileController@saveProfile')
|
||||
->name('saveProfileSettings');
|
||||
|
||||
|
||||
|
||||
Route::get('/settings/account', 'UserController@showAccount')
|
||||
->name('showAccountSettings');
|
||||
|
||||
|
||||
Route::patch('/settings/account/change-password', 'UserController@changePassword')
|
||||
->name('changePassword');
|
||||
|
||||
Route::patch('/settings/account/change-email', 'UserController@changeEmail')
|
||||
->name('changeEmail');
|
||||
|
||||
Route::post('/settings/account/flush-sessions', 'UserController@flushSessions')
|
||||
->name('flushSessions');
|
||||
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue