From 3d9471ca2086f463efd4157ed94f4a8f6de3d1e7 Mon Sep 17 00:00:00 2001 From: Jonny Ngo Luong <jonnynl@stud.ntnu.no> Date: Wed, 7 Apr 2021 19:57:24 +0200 Subject: [PATCH] feat: adding category implemented (#20) co-author: @amalieur --- client/src/app/app-routing.module.ts | 4 +- client/src/app/app.component.html | 1 + client/src/app/app.module.ts | 6 +- .../admin-category.component.html | 9 -- .../admin-category.component.scss | 0 .../admin-category.component.ts | 57 ------------- .../app/categories/admin/admin.component.html | 16 ++++ .../app/categories/admin/admin.component.scss | 50 +++++++++++ .../admin.component.spec.ts} | 12 +-- .../app/categories/admin/admin.component.ts | 85 +++++++++++++++++++ .../post-details/post-details.component.html | 4 +- .../post-details/post-details.component.ts | 2 +- .../controllers/categoryController/index.ts | 10 +-- .../src/controllers/postController/index.ts | 5 +- server/src/models/post.ts | 2 +- 15 files changed, 174 insertions(+), 89 deletions(-) delete mode 100644 client/src/app/categories/admin-category/admin-category.component.html delete mode 100644 client/src/app/categories/admin-category/admin-category.component.scss delete mode 100644 client/src/app/categories/admin-category/admin-category.component.ts create mode 100644 client/src/app/categories/admin/admin.component.html create mode 100644 client/src/app/categories/admin/admin.component.scss rename client/src/app/categories/{admin-category/admin-category.component.spec.ts => admin/admin.component.spec.ts} (52%) create mode 100644 client/src/app/categories/admin/admin.component.ts diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 91980c6..5d71e76 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -7,7 +7,7 @@ import { UserRegistrationFormComponent } from './users/user-registration-form/us import { UserLoginFormComponent } from './users/user-login-form/user-login-form.component'; import { UserProfileComponent } from './users/user-profile/user-profile.component'; import { UserGuestProfileComponent } from './users/user-guest-profile/user-guest-profile.component'; -import { AdminCategoryComponent} from './categories/admin-category/admin-category.component'; +import { AdminComponent} from './categories/admin/admin.component'; import { HomeComponent } from './home/home.component'; import { UserProfileEditFormComponent } from './users/user-profile-edit-form/user-profile-edit-form.component'; @@ -26,7 +26,7 @@ const routes: Routes = [ { path: 'register', component: UserRegistrationFormComponent }, { path: 'login', component: UserLoginFormComponent }, - { path: 'admin/category', component: AdminCategoryComponent } + { path: 'admin/category', component: AdminComponent } ]; @NgModule({ diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 5178819..800e37e 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -2,6 +2,7 @@ <div class="navbar"> <span class="logo" (click)="navigate('/')">SellPoint</span> <nav> + <span *ngIf="user.getIsAdmin" (click)="navigate('/admin/category')">Admin</span> <span (click)="navigate('/annonse')">Annonser</span> <span (click)="navigate('/annonse/ny')">Lag annonse</span> <span *ngIf="!user.getUserId" (click)="navigate('/register')">Registrer</span> diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 5e1d0cf..6e36efd 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -9,8 +9,8 @@ import { PostModule } from './posts/post.module'; import { UserModule } from './users/user.module'; import { AuthModule } from './authentication/auth.module'; import { SharedModule } from './shared/shared.module'; -import { AdminCategoryComponent } from './categories/admin-category/admin-category.component'; import { HomeComponent } from './home/home.component'; +import { AdminComponent } from './categories/admin/admin.component'; export function tokenGetter() { return localStorage.getItem("token"); @@ -19,8 +19,8 @@ export function tokenGetter() { @NgModule({ declarations: [ AppComponent, - AdminCategoryComponent, - HomeComponent + HomeComponent, + AdminComponent, ], imports: [ BrowserModule, diff --git a/client/src/app/categories/admin-category/admin-category.component.html b/client/src/app/categories/admin-category/admin-category.component.html deleted file mode 100644 index c5106d5..0000000 --- a/client/src/app/categories/admin-category/admin-category.component.html +++ /dev/null @@ -1,9 +0,0 @@ -<div class="categoryForm"> - <h3>Legg til kategori</h3> - - <app-text-input [(inputModel)]="name" label="Kategorinavn" (blur)="checkForm()"></app-text-input> - - <p>{{statusMessage}}</p> - - <app-button (click)="addCategory" text="Legg til"></app-button> -</div> \ No newline at end of file diff --git a/client/src/app/categories/admin-category/admin-category.component.scss b/client/src/app/categories/admin-category/admin-category.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/client/src/app/categories/admin-category/admin-category.component.ts b/client/src/app/categories/admin-category/admin-category.component.ts deleted file mode 100644 index 344b98e..0000000 --- a/client/src/app/categories/admin-category/admin-category.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { AuthService } from 'src/app/authentication/auth.service'; -import { PostService } from 'src/app/posts/post.service'; - -@Component({ - selector: 'app-admin-category', - templateUrl: './admin-category.component.html', - styleUrls: ['./admin-category.component.scss'] -}) -export class AdminCategoryComponent implements OnInit { - user: new User(); - name: string = ""; - statusMessage: string = ""; - - constructor(private postService: PostService, private authService: AuthService) { } - - ngOnInit(): void { - this.user = this.authService.getCurrentUser(); - if (this.user.get) - } - - /** - * Validates the form - */ - checkForm(): boolean { - if (this.name == "") { - this.setStatusMessage("Brukernavn kan ikke være tom"); - return false; - } - - this.setStatusMessage(""); - return true; - } - - /** - * Publishes and registers the user if given arguments are valid - */ - registerCategory() { - if (this.checkForm()) { - // Adds user to database and redirects to the homepage afterwards - this.postService.addCategory(name).then(status => { - console.log("Category was added: " + JSON.stringify(status)); - loadCategories(); - }).catch(error => { - console.log("Error adding category: " + error); - }); - } - } - - /** - * Sets the status message for user feedback on form submit - */ - setStatusMessage(message: string) { - this.statusMessage = message; - } -} diff --git a/client/src/app/categories/admin/admin.component.html b/client/src/app/categories/admin/admin.component.html new file mode 100644 index 0000000..5bd7ffe --- /dev/null +++ b/client/src/app/categories/admin/admin.component.html @@ -0,0 +1,16 @@ +<div class="categoryForm"> + <div class="cardWrapper"> + <h3>Alle kategorier</h3> + <div> + <p *ngFor="let category of categories">{{category.getName}}</p> + </div> + </div> + <div class="cardWrapper"> + <h3>Legg til kategori</h3> + <div> + <app-input [(inputModel)]="name" label="Kategorinavn" (blur)="checkForm()"></app-input> + <p class="status">{{statusMessage}}</p> + <app-button (click)="addCategory()" text="Legg til"></app-button> + </div> + </div> +</div> diff --git a/client/src/app/categories/admin/admin.component.scss b/client/src/app/categories/admin/admin.component.scss new file mode 100644 index 0000000..5dc210b --- /dev/null +++ b/client/src/app/categories/admin/admin.component.scss @@ -0,0 +1,50 @@ +:host > .categoryForm { + padding: 5%; + display:flex; + justify-content: center; + flex-direction: column; + align-items: center; + margin-bottom: 50px; + h3 { + font-family: 'Josefin Sans', sans-serif; + font-size: 1.5rem; + font-weight: 500; + padding: 10px; + } + & > div.cardWrapper { + color: #fff; + display: flex; + flex-direction: column; + background: linear-gradient(90deg, #14A35A 0%, #24e072 100%); + padding: 10px; + width: 40%; + min-width: 300px; + max-width: 400px; + margin: 10px; + } +} +div.cardWrapper > div { + color: #000; + display: flex; + flex-direction: column; + gap: 10px; + background-color: #fff; + box-shadow: inset 0px 4px 4px rgb(0 0 0 / 50%); + padding: 20px 10px; +} +p.status { + margin: 10px 0 5px 5px; + font-style: italic; +} +div.other { + font-family: 'Josefin Sans', sans-serif; + display: flex; + justify-content: space-between; + padding: 10px 0 5px 0; + & > a { + color: #000; + &:visited { + color: #000; + } + } +} \ No newline at end of file diff --git a/client/src/app/categories/admin-category/admin-category.component.spec.ts b/client/src/app/categories/admin/admin.component.spec.ts similarity index 52% rename from client/src/app/categories/admin-category/admin-category.component.spec.ts rename to client/src/app/categories/admin/admin.component.spec.ts index 7797ede..eb28e42 100644 --- a/client/src/app/categories/admin-category/admin-category.component.spec.ts +++ b/client/src/app/categories/admin/admin.component.spec.ts @@ -1,20 +1,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { AdminCategoryComponent } from './admin-category.component'; +import { AdminComponent } from './admin.component'; -describe('AdminCategoryComponent', () => { - let component: AdminCategoryComponent; - let fixture: ComponentFixture<AdminCategoryComponent>; +describe('AdminComponent', () => { + let component: AdminComponent; + let fixture: ComponentFixture<AdminComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ AdminCategoryComponent ] + declarations: [ AdminComponent ] }) .compileComponents(); }); beforeEach(() => { - fixture = TestBed.createComponent(AdminCategoryComponent); + fixture = TestBed.createComponent(AdminComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/client/src/app/categories/admin/admin.component.ts b/client/src/app/categories/admin/admin.component.ts new file mode 100644 index 0000000..dababdb --- /dev/null +++ b/client/src/app/categories/admin/admin.component.ts @@ -0,0 +1,85 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { AuthService } from 'src/app/authentication/auth.service'; +import { Category } from 'src/app/models/category.model'; +import { User } from 'src/app/models/user.model'; +import { PostService } from 'src/app/posts/post.service'; + +@Component({ + selector: 'app-admin', + templateUrl: './admin.component.html', + styleUrls: ['./admin.component.scss'] +}) +export class AdminComponent implements OnInit { + user: User = new User(); + categories: Array<Category> = []; + name: string = ""; + statusMessage: string = ""; + + constructor(private postService: PostService, private authService: AuthService, private router: Router) { } + + ngOnInit(): void { + // Restrict page load to logged in admin users only + this.user = this.authService.getCurrentUser(); + if (!this.user.getIsAdmin) { + this.router.navigateByUrl("/"); + } + this.loadCategories(); + } + + /** + * Validates the form + */ + checkForm(): boolean { + if (this.name == "") { + this.setStatusMessage("Kategorinavn kan ikke være tom"); + return false; + } + + this.setStatusMessage(""); + return true; + } + + /** + * Publishes and add category if given arguments are valid + */ + addCategory() { + if (this.checkForm()) { + const category: Category = new Category( + { + id: 0, + name: this.name, + } + ); + // Adds user to database and redirects to the homepage afterwards + this.postService.addCategory(category).then(status => { + console.log("Category was with name: " + this.name+ " was added!"); + this.loadCategories(); + this.categories.push(category); + this.name = ""; // Reset input + }).catch(error => { + console.log("Error adding category: " + error); + }); + } + } + + /* + * Get the categories from database + */ + loadCategories() { + // Gets all categories from database and displays them + this.postService.getAllCategories().then(categories => { + console.log(categories); + this.categories = categories; + }).catch(error => { + console.log(error); + }); + } + + /** + * Sets the status message for user feedback on form submit + */ + setStatusMessage(message: string) { + this.statusMessage = message; + } +} diff --git a/client/src/app/posts/post-details/post-details.component.html b/client/src/app/posts/post-details/post-details.component.html index 28d51fa..db8f81e 100644 --- a/client/src/app/posts/post-details/post-details.component.html +++ b/client/src/app/posts/post-details/post-details.component.html @@ -38,8 +38,8 @@ <a [href]="'mailto:'+owner.getEmail"><app-button class="ownerButton" text="Kontakt selger" (click)="contactPost()"></app-button></a> </div> <div *ngIf="userId == post.getOwner || user.getIsAdmin" class="buttonContainer"> - <app-button class="ownerButton" text="Rediger annonse" (click)="editPost()"></app-button> - <app-button class="ownerButton" text="Slett annonse" (click)="deletePost()"></app-button> + <app-button *ngIf="userId == post.getOwner" class="ownerButton" text="Rediger annonse" (click)="editPost()"></app-button> + <app-button *ngIf="userId == post.getOwner || user.getIsAdmin" class="ownerButton" text="Slett annonse" (click)="deletePost()"></app-button> <div *ngIf="post.getStatus != 1"> <app-button class="ownerButton" text="Marker solgt" (click)="markClosePost()"></app-button> </div> diff --git a/client/src/app/posts/post-details/post-details.component.ts b/client/src/app/posts/post-details/post-details.component.ts index 337853e..3836004 100644 --- a/client/src/app/posts/post-details/post-details.component.ts +++ b/client/src/app/posts/post-details/post-details.component.ts @@ -70,7 +70,7 @@ export class PostDetailsComponent implements OnInit { */ deletePost() { // Check if we are the owner of the post - if (this.userId == this.post.getOwner) { + if (this.userId == this.post.getOwner || this.user.getIsAdmin) { this.postService.deletePost(this.post.getId).then(data => { console.log("Successfully deleted post: " + this.post.getId); this.router.navigateByUrl("/annonse"); diff --git a/server/src/controllers/categoryController/index.ts b/server/src/controllers/categoryController/index.ts index 909626d..c509ee1 100644 --- a/server/src/controllers/categoryController/index.ts +++ b/server/src/controllers/categoryController/index.ts @@ -19,12 +19,12 @@ const category = new Category(); /* ============================= CREATE ============================= */ // Create category `/api/category/` -router.route('/').post(adminPermission, async (request: Request, response: Response) => { - const {categoryName} = request.body; +router.route('/').post(authenticateToken, adminPermission, async (request: Request, response: Response) => { + const {name} = request.body; try { const input = (` INSERT INTO category(name) VALUES (?);`) return response.status(200).json( - await query(input,[categoryName]) + await query(input, [name]) ); } catch (error) { return response.status(400).send("Bad Request"); @@ -52,7 +52,7 @@ router.route('/:categoryid').get(async (request: Request, response: Response) => }); /* ============================= UPDATE ============================= */ -router.route('/').put(authenticateToken, async (request: Request, response: Response) => { +router.route('/').put(authenticateToken, adminPermission, async (request: Request, response: Response) => { const categoryid = request.params.categoryid; const {categoryName} = request.body; try { @@ -64,7 +64,7 @@ router.route('/').put(authenticateToken, async (request: Request, response: Resp /* ============================= DELETE ============================= */ // remove category with id `/api/category/#categoryid` -router.route('/').delete(authenticateToken, async (request: Request, response: Response) => { +router.route('/').delete(authenticateToken, adminPermission, async (request: Request, response: Response) => { const categoryid = request.params.categoryid; try { response.status(200).json(await query("DELETE FROM category WHERE categoryid = ?",[categoryid])); diff --git a/server/src/controllers/postController/index.ts b/server/src/controllers/postController/index.ts index 72539a3..0e17147 100644 --- a/server/src/controllers/postController/index.ts +++ b/server/src/controllers/postController/index.ts @@ -31,13 +31,12 @@ router.route("/").post(async (request: Request, response: Response) => { timestamp: timestamp, owner: owner, categoryid: categoryid, - imageUrl: imageUrl, - status: status, + imageUrl: imageUrl }; if (Object.values(post).filter((p) => p == undefined).length > 0) return response.status(500).send("Error"); - const input = `INSERT INTO post(title, description, price, timestamp, owner, categoryid, imageUrl, status) VALUES (?,?,?,?,?,?,?,?)`; + const input = `INSERT INTO post(title, description, price, timestamp, owner, categoryid, imageUrl) VALUES (?,?,?,?,?,?,?)`; return response.status(200).json(await query(input, Object.values(post))); } catch (error) { return response.status(400).send("Bad Request"); diff --git a/server/src/models/post.ts b/server/src/models/post.ts index 108cb3c..563fd39 100644 --- a/server/src/models/post.ts +++ b/server/src/models/post.ts @@ -7,7 +7,7 @@ interface IPost { owner: number; categoryid: number; imageUrl: string; - status: number; + status?: number; } // Eksporterer IPost til bruk i andre filer. -- GitLab