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

Role based authorization spa #58

Merged
merged 35 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7450fca
Merge branch 'main' of https://github.com/CS3219-AY2425S1/cs3219-ay24…
samuelim01 Sep 27, 2024
b33dc0e
Copy user service
samuelim01 Sep 27, 2024
1291b29
Dockerise user-service
LimZiJia Sep 23, 2024
0d1984e
Dockerise user-service
LimZiJia Sep 23, 2024
d91d061
Merge with main
LimZiJia Sep 23, 2024
3ae459f
Create .gitignore
LimZiJia Sep 23, 2024
dbbef27
Fix POST causing SEGSEGV
LimZiJia Sep 24, 2024
fd7d2bc
Add test
LimZiJia Sep 24, 2024
5dbe575
Basic user service
LimZiJia Sep 27, 2024
667f3b5
Move user service folder
samuelim01 Sep 27, 2024
7f27325
Fix minor user service issues
samuelim01 Sep 27, 2024
ab2ce43
Change login to use username
samuelim01 Sep 27, 2024
5c490d0
Fix user env typo
samuelim01 Sep 27, 2024
661a430
Enable login
LimZiJia Sep 28, 2024
8605f38
Same commit as before
LimZiJia Sep 28, 2024
8be5003
Implement login and register
LimZiJia Sep 28, 2024
dbf74f6
Rename files
LimZiJia Sep 29, 2024
3114a9e
Merge remote-tracking branch 'origin/main' into connect-frontend-with…
LimZiJia Sep 29, 2024
ac136c6
Fix wrong merge
LimZiJia Sep 29, 2024
b01dceb
Init guards
LimZiJia Sep 29, 2024
4d48539
Implement auth-guard and interceptors
LimZiJia Sep 30, 2024
4545df7
Fix prettier
LimZiJia Sep 30, 2024
fb9e5c4
Fix silly issues
LimZiJia Sep 30, 2024
dad4d75
Fix linting
LimZiJia Sep 30, 2024
f23b4fd
Temp commit
LimZiJia Sep 30, 2024
095ca84
Fix error handling
LimZiJia Oct 16, 2024
b7b1c39
Fix linting
LimZiJia Oct 16, 2024
0e8e918
Changed SPA
LimZiJia Oct 16, 2024
1c3d593
Merge branch 'main' into role-based-authorization-spa
LimZiJia Oct 23, 2024
1b8cb53
Merge with main
LimZiJia Oct 23, 2024
d5c4faa
Small modifications
LimZiJia Oct 24, 2024
75d2106
Merge branch 'main' into role-based-authorization-spa
LimZiJia Oct 24, 2024
fcd5022
Use @if directive and fix bugs
LimZiJia Nov 1, 2024
1667d91
Merge branch 'main' into role-based-authorization-spa
LimZiJia Nov 1, 2024
2939dff
Remove extra whitespace
LimZiJia Nov 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"codemirror": "^6.0.1",
"primeflex": "^3.3.1",
"primeicons": "^7.0.0",
"primeng": "^17.18.10",
"primeng": "^17.18.11",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"typeface-poppins": "^1.1.13",
Expand Down
1 change: 0 additions & 1 deletion frontend/src/_interceptors/error.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export class ErrorInterceptor implements HttpInterceptor {
return next.handle(request).pipe(
catchError(err => {
console.error(err);

const errorMessage = err.error.message;
return throwError(() => new Error(errorMessage, { cause: err }));
}),
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/_models/user.service.response.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface UServRes {
message: string;
data: {
id: string;
username: string;
email: string;
accessToken: string;
isAdmin: boolean;
createdAt: string;
};
}
25 changes: 25 additions & 0 deletions frontend/src/_services/authentication.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,29 @@ export class AuthenticationService extends ApiService {
this.userSubject.next(null);
this.router.navigate(['/account/login']);
}

// get user details from user service for authentication
getUserDetails() {
return this.http.get<UServRes>(`${this.apiUrl}/users/${this.userValue?.id}`, { observe: 'response' }).pipe(
map(response => {
if (response.status === 200) {
let user: User = {} as User;
if (response.body) {
const body: UServRes = response.body;
const data = body.data;
user = {
id: data.id,
username: data.username,
email: data.email,
accessToken: data.accessToken,
isAdmin: data.isAdmin,
createdAt: data.createdAt,
};
}
return user;
}
return null;
}),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
<ng-template pTemplate="end">
@if (user) {
<p-menu #menu [model]="items" [popup]="true" appendTo="body"></p-menu>
<p-button [label]="user.username" (onClick)="menu.toggle($event)" icon="pi pi-user" class="nav-dropdown" />
<p-button
[label]="user.username"
(onClick)="menu.toggle($event)"
icon="pi pi-user"
class="nav-dropdown"></p-button>
} @else {
<div class="flex flex-row gap-2 p-2">
<p-button
Expand Down
40 changes: 40 additions & 0 deletions frontend/src/app/questions/questions.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,44 @@

.p-sortable-column:not(.p-highlight):hover {
background-color: #181818 !important;
}

.sliding-panel {
position: fixed;
top: 0;
right: -600px; /* Adjust the width as needed */
width: 600px;
height: 100%;
background-color: #181818 !important;
color: var(--text-color); /* Use theme variable */
box-shadow: -2px 0 5px rgba(0,0,0,0.5);
transition: right 0.3s ease;
z-index: 1000;
}

.sliding-panel.open {
right: 0;
}

.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background-color: #181818 !important;
border-bottom: 1px solid #000000; /* Use theme variable */
}

.panel-content {
padding: 1rem;
line-height: 1.6; /* Adjust line height for better readability */
color: #ffffff; /* Ensure text color is readable */
}

.panel-content p {
margin-bottom: 1rem; /* Add margin to paragraphs for spacing */
}

tr:hover {
background-color: rgba(0, 0, 0, 0.1);
}
187 changes: 112 additions & 75 deletions frontend/src/app/questions/questions.component.html
Original file line number Diff line number Diff line change
@@ -1,80 +1,103 @@
<div class="card mx-8">
<p-progressSpinner
class="flex align-items-center justify-content-center h-screen"
*ngIf="loading"
styleClass="w-4rem h-4rem"
strokeWidth="8"
animationDuration=".5s" />
<p-toast />
<ng-container *ngIf="!loading">
<p-toolbar styleClass="mt-4 mb-2 gap-2">
<div class="p-justify-end">
<p-button
icon="pi pi-plus"
severity="primary"
[outlined]="true"
label="New"
class="mr-2"
(onClick)="openNewQuestion()" />
<p-button
icon="pi pi-trash"
severity="danger"
label="Delete"
(onClick)="deleteSelectedQuestions()"
[disabled]="!selectedQuestions || !selectedQuestions.length" />
</div>
</p-toolbar>
<p-table
sortField="id"
[sortOrder]="1"
[columns]="cols"
[value]="questions"
[(selection)]="selectedQuestions"
datakey="id"
[tableStyle]="{ 'min-width': '50rem' }"
[paginator]="true"
[rows]="5"
[rowsPerPageOptions]="[5, 10, 20]"
styleClass="p-datatable-gridlines-striped">
<ng-template pTemplate="caption">
<div class="flex">
<h3 class="m-0">Manage Questions</h3>
@if (loading) {
<p-progressSpinner
class="flex align-items-center justify-content-center h-screen"
styleClass="w-4rem h-4rem"
strokeWidth="8"
animationDuration=".5s" />
<p-toast />
} @else {
<ng-container>
<div
[ngStyle]="
isAdmin ? { 'max-width': '1150px', margin: '0 auto' } : { 'max-width': '900px', margin: '0 auto' }
">
@if (isAdmin) {
<p-toolbar styleClass="mt-4 mb-2 gap-2">
<div class="p-justify-end">
<p-button
icon="pi pi-plus"
severity="primary"
[outlined]="true"
label="New"
class="mr-2"
(onClick)="openNewQuestion()" />
<p-button
icon="pi pi-trash"
severity="danger"
label="Delete"
(onClick)="deleteSelectedQuestions()"
[disabled]="!selectedQuestions || !selectedQuestions.length" />
</div>
</p-toolbar>
} @else {
<div style="height: 50px"></div>
}
<div class="table-container">
<p-table
sortField="id"
[sortOrder]="1"
[columns]="cols"
[value]="questions"
[(selection)]="selectedQuestions"
datakey="id"
[tableStyle]="{ 'table-layout': 'fixed', width: '100%', 'text-align': 'center' }"
[paginator]="true"
[rows]="10"
[rowsPerPageOptions]="[10, 25, 50]"
styleClass="p-datatable-gridlines-striped">
<ng-template pTemplate="caption">
<div class="flex">
<h3 class="m-0">Questions</h3>
</div>
</ng-template>
<ng-template pTemplate="header" let-columns>
<tr>
@if (isAdmin) {
<th style="width: 10%"><p-tableHeaderCheckbox /></th>
<th pSortableColumn="id" style="width: 13%">Id<p-sortIcon field="id" /></th>
<th style="width: 27%">Title</th>
<th style="width: 30%">Topics</th>
<th style="width: 10%">Difficulty</th>
<th style="width: 10%"></th>
} @else {
<th style="width: 15%">Id</th>
<th style="width: 35%">Title</th>
<th style="width: 37%">Topics</th>
<th style="width: 13%">Difficulty</th>
}
</tr>
</ng-template>
<ng-template pTemplate="body" let-question>
<tr (click)="onRowSelect(question)">
@if (isAdmin) {
<td><p-tableCheckbox [value]="question" /></td>
<td>{{ question.id }}</td>
<td>{{ question.title }}</td>
<td>{{ question.topics.join(', ') }}</td>
<td>{{ question.difficulty }}</td>
<td>
<p-button
label="Edit"
severity="primary"
icon="pi pi-file-edit"
class="mr-2"
[text]="true"
(onClick)="editQuestion(question)" />
</td>
} @else {
<td>{{ question.id }}</td>
<td>{{ question.title }}</td>
<td>{{ question.topics.join(', ') }}</td>
<td>{{ question.difficulty }}</td>
}
</tr>
</ng-template>
</p-table>
</div>
</ng-template>
<ng-template pTemplate="header" let-columns>
<tr>
<th style="width: 10%"><p-tableHeaderCheckbox /></th>
<th pSortableColumn="id" style="width: 10%">Id <p-sortIcon field="id" /></th>
<th style="width: 10%">Title</th>
<th style="width: 40%">Description</th>
<th style="width: 10%">Topics</th>
<th style="width: 10%">Difficulty</th>
<th style="width: 10%"></th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-question>
<tr>
<td>
<p-tableCheckbox [value]="question" />
</td>
<td>{{ question.id }}</td>
<td>{{ question.title }}</td>
<td style="white-space: pre-wrap">{{ question.description }}</td>
<td>{{ question.topics.join(', ') }}</td>
<td>{{ question.difficulty }}</td>
<td>
<p-button
label="Edit"
severity="primary"
icon="pi pi-file-edit"
class="mr-2"
[text]="true"
(onClick)="editQuestion(question)" />
</td>
</tr>
</ng-template>
</p-table>
</ng-container>
</div>
</ng-container>
}
<app-question-dialog
[isDialogVisible]="isDialogVisible"
[question]="question"
Expand All @@ -85,4 +108,18 @@ <h3 class="m-0">Manage Questions</h3>
(successfulRequest)="onSuccessfulRequest($event)">
</app-question-dialog>
<p-confirmDialog [style]="{ width: '450px' }" />
<div class="sliding-panel" [class.open]="isPanelVisible">
<div class="panel-header">
<h4>{{ clickedOnQuestion?.title }}</h4>
<p-button
icon="pi pi-times"
severity="secondary"
label="Close"
(onClick)="closePanel()"
class="p-button-text" />
</div>
<div class="panel-content">
<p style="white-space: pre-wrap">{{ clickedOnQuestion?.description }}</p>
</div>
</div>
</div>
Loading