Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic Multi-User Setup #217

Merged
merged 5 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 8 additions & 6 deletions app/Http/Controllers/HomeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use App\Http\Requests\Home\GetConfigRequest;

class HomeController extends Controller {

private $statisticsService;
private $goalService;

Expand All @@ -29,12 +29,14 @@ public function index() {
$selectedLanguage = Auth::user()->selected_language;
$userCount = User::count();
$userName = Auth::user()->name;
$isAdmin = Auth::user()->is_admin;
$theme = $_COOKIE['theme'] ?? 'light';

return view('home', [
'language' => $selectedLanguage,
'userCount' => $userCount,
'userName' => $userName,
'isAdmin' => $isAdmin,
'theme' => $theme
]);
}
Expand Down Expand Up @@ -78,7 +80,7 @@ public function getConfig($configPath, GetConfigRequest $request) {

public function getUserManualTree() {
$manualTree = [];

$path = public_path('./../manual/');
$files = scandir($path);

Expand Down Expand Up @@ -108,7 +110,7 @@ public function getUserManualTree() {
$subPageName = str_replace("\r\n", '', $subPageName);
$subPageName = str_replace("\n", '', $subPageName);
$subPageName = str_replace("\n", '', $subPageName);

$subPage = new \stdClass();
$subPage->id = $index;
$subPage->name = $subPageName;
Expand All @@ -118,10 +120,10 @@ public function getUserManualTree() {
$index ++;
}
}

fclose($handle);
}

if (count($subPages)) {
$page->children = $subPages;
}
Expand Down
9 changes: 7 additions & 2 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ public function __construct(UserService $userService) {

}

public function isAdmin() {
$isAdmin = Auth::user()->is_admin;
return response($isAdmin, 200);
}

public function isUserPasswordChanged() {
$passwordChanged = Auth::user()->password_changed;
return response($passwordChanged, 200);
Expand All @@ -40,13 +45,13 @@ public function getUsers() {
public function updatePassword(UpdatePasswordRequest $request) {
$user = Auth::user();
$password = $request->post('password');

try {
$this->userService->updatePassword($user, $password);
} catch(\Exception $e) {
abort(500, $e->getMessage());
}

return response()->json('Password has been updated successfully.', 200);
}

Expand Down
1 change: 1 addition & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\AdminMiddleware::class,
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
Expand Down
26 changes: 26 additions & 0 deletions app/Http/Middleware/AdminMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AdminMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if (!Auth::check() || !Auth::user()->is_admin) {
// If the user is not logged in or not an admin, redirect or handle as necessary
return response()->json(['error' => 'You do not have permission to access this resource.'], 403);
}
return $next($request);
}
}
13 changes: 12 additions & 1 deletion resources/js/components/Admin/AdminSettingsLayout.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<v-container>
<v-container v-if="isAdmin">
<v-tabs v-model="tab" background-color="white" class="rounded-lg border overflow-hidden">
<v-tab>Users</v-tab>
<v-tab>Dictionaries</v-tab>
Expand All @@ -21,18 +21,29 @@
</v-tab-item>
</v-tabs-items>
</v-container>
<v-container v-else-if="!loading">
You do not have permission to access this section.
</v-container>
</template>

<script>
export default {
data: function() {
return {
tab: 0,
isAdmin: false,
loading: true,
}
},
props: {
language: String
},
beforeMount() {
axios.get('/users/is-admin').then((response) => {
this.isAdmin = response.data;
this.loading = false;
});
},
mounted() {
},
methods: {
Expand Down
16 changes: 8 additions & 8 deletions resources/js/components/Admin/AdminUserSettings.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div id="admin-user-settings">
<div id="admin-user-settings" v-if="!error && !loading">
jacovanc marked this conversation as resolved.
Show resolved Hide resolved
<!-- Add or edit user dialog -->
<admin-edit-user-dialog
<admin-edit-user-dialog
v-if="editDialog.active"
v-model="editDialog.active"
:_user-id="editDialog.userId"
Expand All @@ -10,12 +10,12 @@
:_is-admin="editDialog.isAdmin"
@user-saved="closeUserDialog"
></admin-edit-user-dialog>

<!-- Title subheader -->
<div class="d-flex subheader mt-4 mb-4 px-2 ">
Users
<v-spacer />
<v-btn rounded dark color="primary" @click="addUser" disabled>
<v-btn rounded dark color="primary" @click="addUser" >
<v-icon class="mr-1">mdi-plus</v-icon>
Add user
</v-btn>
Expand All @@ -41,15 +41,15 @@
{{ user.is_admin ? 'Yes' : 'No' }}
</td>
<td class="text-center">
<v-btn
icon
<v-btn
icon
title="Edit"
@click="editUser(user)"
>
<v-icon>mdi-pencil</v-icon>
</v-btn>
<v-btn
icon
<v-btn
icon
title="Delete"
color="error"
>
Expand Down
47 changes: 26 additions & 21 deletions resources/js/components/Layout.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<v-app :class="{'eink': theme == 'eink', 'dark': theme == 'dark'}">

<!-- Dialogs -->
<start-review-dialog v-model="startReviewDialog" />
<logout-dialog v-model="logoutDialog"/>
Expand All @@ -9,13 +9,13 @@
<theme-selection-dialog v-model="themeSelectionDialog" @input="updateTheme"></theme-selection-dialog>
<language-selection-dialog v-model="languageSelectionDialog"></language-selection-dialog>
<v-navigation-drawer
id="navigation-drawer"
app
id="navigation-drawer"
app
dense
:class="{'eink': theme == 'eink'}"
:mini-variant="$vuetify.breakpoint.md || navbarCollapsed"
:permanent="$vuetify.breakpoint.mdAndUp"
v-model="drawer"
:class="{'eink': theme == 'eink'}"
:mini-variant="$vuetify.breakpoint.md || navbarCollapsed"
:permanent="$vuetify.breakpoint.mdAndUp"
v-model="drawer"
color="foreground"
>
<!-- Logo -->
Expand All @@ -27,10 +27,10 @@

<v-list nav shaped dense class="pl-0">
<!-- Navigation buttons -->
<v-list-item
class="navigation-button"
v-for="(item, index) in navigation"
:key="index"
<v-list-item
class="navigation-button"
v-for="(item, index) in navigation"
:key="index"
:to="item.url"
@click="navigationClick(item.name, $event)"
>
Expand Down Expand Up @@ -72,7 +72,7 @@
<v-icon>mdi-palette</v-icon>
</v-btn>
<v-btn id="language" rounded text class="mini-drawer-button" @click="languageSelectionDialog = true" title="Select language">
<v-img :src="'/images/flags/' + selectedLanguage.toLowerCase() + '.png'" max-width="31" height="20"></v-img>
<v-img :src="'/images/flags/' + selectedLanguage.toLowerCase() + '.png'" max-width="31" height="20"></v-img>
</v-btn>
</template>
</template>
Expand All @@ -84,9 +84,9 @@
<span>More</span>
<v-icon>mdi-menu</v-icon>
</v-btn><v-spacer></v-spacer>
<v-btn
<v-btn
class="text-decoration-none"
grow
grow
v-for="(item, index) in navigation"
:key="index"
:to="item.url"
Expand All @@ -97,7 +97,6 @@
</v-btn>
</v-bottom-navigation>
</template>

<v-main :style="{background: $vuetify.theme.currentTheme.background}" :class="{ eink: theme == 'eink'}">
<router-view :user-count="$props._userCount" :language="selectedLanguage" :key="$route.fullPath"></router-view>
</v-main>
Expand Down Expand Up @@ -157,12 +156,6 @@
icon: 'mdi-account-cog',
bottomNav: false,
},
{
name: 'Admin settings',
url: '/admin',
icon: 'mdi-shield-lock',
bottomNav: false,
},
{
name: 'User manual',
url: '/user-manual',
Expand All @@ -179,6 +172,7 @@
default: '',
},
_userCount: Number,
_isAdmin: Boolean,
},
beforeMount() {
if (this.$props._selectedLanguage == 'japanese') {
Expand All @@ -190,6 +184,17 @@
});
}

console.log("is admin: " + this.$props._isAdmin);

if(this.$props._isAdmin == true) {
this.navigation.push({
name: 'Admin settings',
url: '/admin',
icon: 'mdi-shield-lock',
bottomNav: false,
});
}

// load theme
ThemeService.loadTheme(defaultThemes, this.$cookie, this.$vuetify);

Expand Down
2 changes: 1 addition & 1 deletion resources/views/home.blade.php
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
@extends('layouts.user')
@section('content')<layout _user-name="{{ $userName }}" :_user-count="{{ $userCount }}" _selected-language="{{ $language }}"></layout>@endsection
@section('content')<layout _user-name="{{ $userName }}" :_user-count="{{ $userCount }}" _is-admin="{{ $isAdmin }}" _selected-language="{{ $language }}"></layout>@endsection
26 changes: 15 additions & 11 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@
Route::group(['middleware' => 'web'], function () {
Route::post('/users/create', [App\Http\Controllers\UserController::class, 'createUser']);
});

Route::group(['middleware' => ['auth', 'web']], function () {
Route::get ('/users/get', [App\Http\Controllers\UserController::class, 'getUsers']);

Route::group(['middleware' => 'admin'], function () {
Route::get ('/users/get', [App\Http\Controllers\UserController::class, 'getUsers']);
Route::post('/dictionary/update', [App\Http\Controllers\DictionaryController::class, 'updateDictionary']);
// Add other routes that need admin permission here.
// Or break this up into multple groups so that we can keep them organised in their relevant sections
});

// users
Route::get ('/users/get', [App\Http\Controllers\UserController::class, 'getUsers']);
Route::get('/users/is-admin', [App\Http\Controllers\UserController::class, 'isAdmin']); // Adding a isAdmin check endpoint which is used on the admin settings adminLayout page.
Route::post('/users/update', [App\Http\Controllers\UserController::class, 'updateUser']);
Route::post('/users/update-password', [App\Http\Controllers\UserController::class, 'updatePassword']);
Route::get ('/users/is-password-changed', [App\Http\Controllers\UserController::class, 'isUserPasswordChanged']);
Expand Down Expand Up @@ -67,7 +72,7 @@
Route::get('/vocabulary/search/{text}/{stage}/{book}/{chapter}/{translation}/{phrases}/{orderBy}/{page}', [App\Http\Controllers\HomeController::class, 'index']);
Route::get('/kanji/search', [App\Http\Controllers\HomeController::class, 'index']);
Route::get('/kanji/{character}', [App\Http\Controllers\HomeController::class, 'index']);

// home
Route::post('/statistics/get', [App\Http\Controllers\HomeController::class, 'getStatistics']);
Route::get('/language/change/{language}', [App\Http\Controllers\HomeController::class, 'changeLanguage']);
Expand All @@ -90,8 +95,8 @@
Route::post('/settings/global/update', [App\Http\Controllers\SettingsController::class, 'updateGlobalSettings']);
Route::post('/settings/user/get', [App\Http\Controllers\SettingsController::class, 'getUserSettingsByName']);
Route::post('/settings/user/update', [App\Http\Controllers\SettingsController::class, 'updateUserSettings']);
// images

// images
Route::get('/images/book_images/{fileName}', [App\Http\Controllers\ImageController::class, 'getBookImage']);

// dictionaries
Expand All @@ -103,7 +108,6 @@
Route::get('/dictionaries/deepl/is-enabled', [App\Http\Controllers\DictionaryController::class, 'isDeeplEnabled']);
Route::get('/dictionaries/get', [App\Http\Controllers\DictionaryController::class, 'getDictionaries']);
Route::get('/dictionary/get/{dictionaryId}', [App\Http\Controllers\DictionaryController::class, 'getDictionary']);
Route::post('/dictionary/update', [App\Http\Controllers\DictionaryController::class, 'updateDictionary']);
Route::post('/dictionary/search', [App\Http\Controllers\DictionaryController::class, 'searchDefinitions']);
Route::post('/dictionary/search-for-hover-vocabulary', [App\Http\Controllers\DictionaryController::class, 'searchDefinitionsForHoverVocabulary']);
Route::post('/dictionary/search/inflections', [App\Http\Controllers\DictionaryController::class, 'searchInflections']);
Expand All @@ -126,7 +130,7 @@
Route::get ('/vocabulary/example-sentence/{targetType}/{targetId}', [App\Http\Controllers\VocabularyController::class, 'getExampleSentence']);
Route::post('/kanji/search', [App\Http\Controllers\VocabularyController::class, 'searchKanji']);
Route::post('/kanji/details', [App\Http\Controllers\VocabularyController::class, 'getKanjiDetails']);

// review
Route::post('/reviews', [App\Http\Controllers\ReviewController::class, 'getReviewItems']);
Route::post('/reviews/update', [App\Http\Controllers\ReviewController::class, 'updateReadWordsGoal']);
Expand All @@ -136,7 +140,7 @@
Route::post('/flashcards/delete', [App\Http\Controllers\FlashcardController::class, 'deleteFlashcardCollection']);
Route::post('/flashcards/get', [App\Http\Controllers\FlashcardController::class, 'getFlashcardCollection']);
Route::post('/flashcards/save', [App\Http\Controllers\FlashcardController::class, 'saveFlashcardCollection']);

// anki
Route::post('/anki/add-card', [App\Http\Controllers\AnkiController::class, 'addCardToAnki']);

Expand All @@ -146,7 +150,7 @@
Route::post('/books/create', [App\Http\Controllers\BookController::class, 'createBook']);
Route::post('/books/update', [App\Http\Controllers\BookController::class, 'updateBook']);
Route::post('/books/delete', [App\Http\Controllers\BookController::class, 'deleteBook']);

// chapters
Route::post('/chapters', [App\Http\Controllers\ChapterController::class, 'getChaptersForBook']);
Route::post('/chapters/get/reader', [App\Http\Controllers\ChapterController::class, 'getChapterForReader']);
Expand All @@ -161,4 +165,4 @@
Route::post('/youtube/get-subtitle-list', [App\Http\Controllers\ImportController::class, 'getYoutubeSubtitles']);
Route::post('/subtitle/get-subtitle-file-content', [App\Http\Controllers\ImportController::class, 'getSubtitleFileContent']);
Route::post('/website/get-text', [App\Http\Controllers\ImportController::class, 'getWebsiteText']);
});
});