Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • miburgos/spring2021-sellpoint
  • tdt4140-group-58/spring2021-sellpoint
2 results
Show changes
Commits on Source (118)
Showing
with 2332 additions and 19870 deletions
......@@ -18,3 +18,8 @@ yarn-error.log*
.idea
.vscode
# keys and .env
jwtRS256.key
jwtRS256.key.pub
server/.env
\ No newline at end of file
image: node:14.16.0-alpine
stages:
- install
- build_and_test
variables:
JWT_KEY: "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----"
cache:
paths:
- node_modules/
- client/node_modules/
- server/node_modules/
install:
stage: install
script:
- npm --silent install
- cd server && npm --silent install
- cd ../client && npm --silent install
only:
changes:
- package-lock.json
refs:
- master
- merge_requests
build_and_test:
stage: build_and_test
script:
- npm build
after_script:
- cd server && npm test
only:
refs:
- master
- merge_requests
\ No newline at end of file
This diff is collapsed.
......@@ -19,16 +19,17 @@
"@angular/platform-browser": "~11.1.1",
"@angular/platform-browser-dynamic": "~11.1.1",
"@angular/router": "~11.1.1",
"rxjs": "~6.6.0",
"@auth0/angular-jwt": "^5.0.2",
"rxjs": "^6.6.6",
"tslib": "^2.0.0",
"zone.js": "~0.11.3"
"zone.js": "^0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1101.2",
"@angular/cli": "~11.1.2",
"@angular-devkit/build-angular": "^0.1101.4",
"@angular/cli": "^11.1.4",
"@angular/compiler-cli": "~11.1.1",
"@types/jasmine": "~3.6.0",
"@types/node": "^12.11.1",
"@types/jasmine": "^3.6.6",
"@types/node": "^12.20.5",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
......@@ -40,6 +41,6 @@
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~4.1.2"
"typescript": "^4.1.5"
}
}
......@@ -3,15 +3,33 @@ import { RouterModule, Routes } from '@angular/router';
import { PostDetailsComponent } from './posts/post-details/post-details.component';
import { PostFormComponent } from './posts/post-form/post-form.component';
import { PostListComponent } from './posts/post-list/post-list.component';
import { UserRegistrationFormComponent } from './users/user-registration-form/user-registration-form.component';
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 { AdminComponent} from './categories/admin/admin.component';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'annonse/ny', component: PostFormComponent },
{ path: 'annonse/rediger/:id', component: PostFormComponent },
{ path: 'annonse', component: PostListComponent },
{ path: 'annonse/:id', component: PostDetailsComponent }
{ path: 'annonse/:id', component: PostDetailsComponent },
{ path: 'user/:id', component: UserGuestProfileComponent },
{ path: 'profil', component: UserProfileComponent },
{ path: 'profil/rediger', component: UserRegistrationFormComponent},
{ path: 'register', component: UserRegistrationFormComponent },
{ path: 'login', component: UserLoginFormComponent },
{ path: 'admin/category', component: AdminComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
export class AppRoutingModule { }
\ No newline at end of file
<h1>SellPoint</h1>
<div class="body">
<div class="navbar">
<span class="logo" (click)="navigate('/')">
<img src="../assets/img/SellPointLogo1.png" alt="logo">
</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>
<span *ngIf="!user.getUserId" (click)="navigate('/login')">Logg inn</span>
<span *ngIf="user.getUserId" (click)="navigate('/profil')">Profil</span>
<span *ngIf="user.getUserId" (click)="logout()">Logg ut</span>
</nav>
</div>
<router-outlet></router-outlet>
\ No newline at end of file
<div class="splash">
<div class="title"><h1>SELLPOINT</h1></div>
<div class="wave">
<div class="waveImg"></div>
</div>
</div>
<div class="wrapper">
<router-outlet></router-outlet>
</div>
</div>
<div class="footer">
<div class="logo">
<a style="display: block;" href="/"><img src="../assets/img/SellPointLogo2.png" alt="logo"></a>
</div>
<div class="info">
<div class="bedrift">
<h3>For bedrifter</h3>
<ul>
<li>Lorem ipsum</li>
<li>Lorem ipsum</li>
<li>Lorem ipsum</li>
</ul>
</div>
<div class="omoss">
<h3>Om SellPoint</h3>
<ul>
<li>Lorem ipsum</li>
<li>Lorem ipsum</li>
<li>Lorem ipsum</li>
</ul>
</div>
<div class="personvern">
<h3>Personvern</h3>
<ul>
<li>Lorem ipsum</li>
<li>Lorem ipsum</li>
<li>Lorem ipsum</li>
</ul>
</div>
</div>
</div>
div.body{
min-height: calc(100vh - 200px);
margin-bottom: 50px;
overflow-y: hidden;
}
div.navbar {
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
height: 62px;
font-family: 'Josefin Sans', sans-serif;
padding-top: 8px;
span.logo {
padding: 10px;
width: 200px;
margin-left: 10px;
font-size: 40px;
font-weight: bold;
cursor: pointer;
img {
width: 170px;
transform: translateY(3px);
}
}
nav {
span{
padding: 10px;
cursor: pointer;
margin: 20px;
font-size: 25px;
background-color: #fff;
}
span:hover{
background-color: #eee;
}
}
}
div.splash {
position: absolute;
width: 100%;
height: 55vh;
background-color: springgreen;
background-image: url("../assets/img/backgroundImage.png");
background-size: cover;
display: flex;
justify-content: space-between;
overflow: hidden;
color: #ffffff;
font-family: 'Inter', sans-serif;
button {
color: #ffffff;
text-decoration: none;
}
div {
position: relative;
}
div.title {
position: absolute;
top: 50px;
left: 50%;
transform: translateX(-50%);
font-family: 'Inter', sans-serif;
font-size: 2em;
text-shadow: -2px 2px 3px #000000;
h1 {
letter-spacing: 10px;
}
}
img {
position: absolute;
height: 100%;
bottom: -10%;
object-fit: cover;
}
div.wave {
position: absolute;
left: 0;
bottom: 0;
position: absolute;
top: 250px;
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
div.waveImg {
position: absolute;
bottom: 0;
width: 100%;
height: 110%;
background-image: url(../assets/img/wave2.svg);
background-repeat: no-repeat;
background-attachment: scroll;
background-position: 0% 0%;
background-size: 100vw auto;
}
}
}
div.wrapper {
position: relative;
top: 125px;
padding: 5%;
width: 100%;
height: 100%;
}
div.footer {
color: #ffffff;
background-color: rgb(80, 80, 80);
display: flex;
justify-content: space-between;
align-items: center;
font-family: 'Josefin Sans', sans-serif;
clear: both;
height: 200px;
width: 100%;
div.info {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-right: 5%;
width: 400px;
ul {
padding-left: 20px;
}
}
div.logo {
margin-left: 5%;
}
}
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
......@@ -6,7 +7,8 @@ describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
RouterTestingModule,
HttpClientTestingModule
],
declarations: [
AppComponent
......
import { Component
} from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { AuthService } from './authentication/auth.service';
import { User } from './models/user.model';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'client';
export class AppComponent implements OnInit {
title: string = 'client';
user: User;
userSubscription: Subscription;
constructor(private authService: AuthService, private router: Router){}
ngOnInit() {
this.user = this.authService.getCurrentUser(false);
this.userSubscription = this.authService.userObservable.subscribe(user => {
this.user = user;
});
}
navigate(url) {
this.router.navigateByUrl(url);
}
logout() {
this.authService.logout();
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { JwtModule } from "@auth0/angular-jwt";
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
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 { HomeComponent } from './home/home.component';
import { AdminComponent } from './categories/admin/admin.component';
export function tokenGetter() {
return localStorage.getItem("token");
}
@NgModule({
declarations: [
AppComponent,
HomeComponent,
AdminComponent,
],
imports: [
BrowserModule,
UserModule,
AuthModule,
AppRoutingModule,
PostModule,
SharedModule,
HttpClientModule
HttpClientModule,
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
allowedDomains: ["localhost"],
disallowedRoutes: [""],
},
}),
],
providers: [],
bootstrap: [AppComponent]
......
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '../shared/shared.module';
@NgModule({
declarations: [],
imports: [
CommonModule
]
})
export class AuthModule { }
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, RouterTestingModule ]
});
service = TestBed.inject(AuthService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { User } from '../models/user.model';
import { tap, shareReplay } from 'rxjs/operators';
import { Router } from '@angular/router';
import { UserService } from '../users/user.service';
import { Subject } from 'rxjs';
interface IUserLogin {
username: string;
password: string;
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
loginUrl = "api/auth/login";
registrationUrl = "api/auth/register";
userObservable: Subject<User> = new Subject<User>();
constructor(private http: HttpClient, private router: Router, private userService: UserService) { }
getCurrentUser(route=true): User{
// Check for token expiration
if (this.checkTokenExpiration(route)) { // redirects to "/" if token is expired
// Get user data from JWT token
const token = localStorage.getItem('token');
const user_data = JSON.parse(atob(token.split(".")[1])).data[0];
return new User(user_data);
}
return new User();
}
/**
* Logins an user, if given correct combination of username and password.
*/
login(body: IUserLogin): Promise<string> {
return new Promise<string>(
(resolve, reject) => {
this.login_user(body).subscribe((data: any) => {
try {
resolve(data.token);
} catch (err: any) {
reject(err);
}
},
(err: any) => {
console.log(err.message);
reject(err);
});
}
);
}
private login_user(body: IUserLogin) {
// Pipes output to setSession function if a valid user is returned
return this.http.post(this.loginUrl, body).pipe(
tap(res =>this.setSession(res)),
shareReplay()
);
}
// Set authentication token on localStorage if a valid user is received
private setSession(authResult) {
localStorage.setItem('token', authResult.token);
this.userObservable.next(this.getCurrentUser());
}
/**
* Checks validity of token, redirects to homepage and removes it if it is expired
*/
checkTokenExpiration(route) {
const token = localStorage.getItem("token");
if (token) {
const {iat, exp} = JSON.parse(atob(token?.split(".")[1]));
if (iat && exp) {
const issued = new Date(iat*1000);
const expires = new Date(exp*1000);
const now = new Date();
// Expired token
if (now < issued || now >= expires) {
this.logout();
if (route) {
this.router.navigate(["/login"], {replaceUrl: true});
}
return false
}
return true;
}
}
if (route) {
this.router.navigate(["/login"], {replaceUrl: true});
}
return false
}
/**
* Logout a user and redirects to the homepage
*/
logout() {
localStorage.removeItem("token");
this.router.navigateByUrl("/");
this.userObservable.next(new User());
}
/**
* Register a user, if not duplicate, add to database.
*/
registerUser(user: User): Promise<string> {
return new Promise<string>(
(resolve, reject) => {
this.register_user(user).subscribe((data: any) => {
try {
resolve(data.data);
} catch (err: any) {
reject(err);
}
},
(err: any) => {
console.log(err.message);
reject(err);
});
}
);
}
private register_user(user: User) {
return this.http.post(this.registrationUrl, user.serialize());
}
}
<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>
: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
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminComponent } from './admin.component';
describe('AdminComponent', () => {
let component: AdminComponent;
let fixture: ComponentFixture<AdminComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminComponent ],
imports: [
HttpClientTestingModule,
RouterTestingModule.withRoutes([
{ path: 'admin/category', component: AdminComponent}
])
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AdminComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
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;
}
}
<div class="home">
<div class="categoryWrapper">
<p>Kategorier</p>
<div class="whiteBox"></div>
</div>
<div class="cta">
<h2>Lorem Ipsum</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<div class="buttons">
<button (click)="navigate('/register')" class="btn">Registrer deg!</button>
<button (click)="navigate('/')" class="btn pink">Les mer</button>
</div>
</div>
</div>
<div class="postContainer">
<h2>Annonser i nærheten av deg</h2>
<p *ngIf="this.user.getUserId == 0">Logg inn for å se annonsene...</p>
<p *ngIf="this.user.getUserId != 0 && allPosts.length == 0">Ingen annonser i nærheten av deg...</p>
<app-post-thumbnail *ngFor="let post of allPosts" [post]="post"></app-post-thumbnail>
</div>
\ No newline at end of file
div.home {
position: relative;
width: 100%;
height: 600px;
background-size: cover;
display: flex;
justify-content: space-between;
overflow: hidden;
color: #ffffff;
font-family: 'Inter', sans-serif;
button {
color: #ffffff;
text-decoration: none;
}
div {
position: relative;
}
div.categoryWrapper {
opacity: 0; /* hided as it is not used */
padding: 10px;
margin-left: 5%;
background: linear-gradient(90deg, #14A35A 0%, #24e072 100%);
width: 40%;
height: 300px;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.5);
p {
padding-left: 10px;
padding-bottom: 5px;
margin-bottom: 5px;
border-bottom: white solid 1px;
width: 105px;
}
div.whiteBox {
width: 100%;
height: 250px;
background-color: #ffffff;
box-shadow: inset 0px 4px 4px rgba(0, 0, 0, 0.5);
}
}
div.cta {
color: #030303;
text-align: right;
margin-right: 5%;
margin-top: 60px;
width: 400px;
z-index: 2;
div.buttons {
display: flex;
text-align: center;
justify-content: flex-end;
}
button.btn {
background: #13D05E;
width: 200px;
margin: 10px 0 10px 10px;
padding: 20px;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 4px 4px rgba(0, 0, 0, 0.25);
font-family: 'Josefin Sans', sans-serif;
font-size: 20px;
border: none;
cursor: pointer;
}
button.pink {
background: #FFA1A1;
}
}
}
div.postContainer{
width: 100%;
display: grid;
grid-template-columns: repeat(auto-fill, 384px);
gap: 30px;
margin-bottom: 80px;
transform: translateY(-150px);
justify-content: center;
h2 {
font-family: 'Josefin Sans', sans-serif;
position: absolute;
top: -50px;
left: 50%;
transform: translateX(-50%);
}
p {
font-family: 'Josefin Sans', sans-serif;
position: absolute;
left: 50%;
transform: translateX(-50%);
}
}
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../authentication/auth.service';
import { Post } from '../models/post.model';
import { User } from '../models/user.model';
import { PostService } from '../posts/post.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
allPosts: Array<Post> = [];
user: User = new User();
constructor(private postService: PostService, private authService: AuthService, private router: Router){}
ngOnInit(): void {
// Gets current user information
this.user = this.authService.getCurrentUser(false);
this.getPosts();
}
navigate(url) {
this.router.navigateByUrl(url);
}
getPosts() {
if (this.user.getUserId != 0) {
this.postService.getPostsByCategory(undefined, [this.user.getLocation], undefined, undefined, undefined).then(posts => {
this.allPosts = posts.filter((post: Post) => post.getStatus == 0); // Filter out closed post
}).catch(error => {
console.log(error);
});
}
}
}