diff --git a/app.js b/app.js
index ce38cbf..e61d1be 100644
--- a/app.js
+++ b/app.js
@@ -4,11 +4,16 @@ var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
+var mongoose = require('mongoose');
var appRoutes = require('./routes/app');
+var messagesRoutes = require('./routes/messages.js');
+var usersRoutes = require('./routes/users.js');
var app = express();
+mongoose.connect('localhost:27017/angular4-node')
+
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
@@ -28,6 +33,8 @@ app.use(function (req, res, next) {
next();
});
+app.use('/message', messagesRoutes);
+app.use('/user', usersRoutes);
app.use('/', appRoutes);
// catch 404 and forward to error handler
diff --git a/assets/app/app.component.html b/assets/app/app.component.html
index ba7c290..44cf02d 100644
--- a/assets/app/app.component.html
+++ b/assets/app/app.component.html
@@ -1 +1,6 @@
-
Hello World!
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/assets/app/app.component.ts b/assets/app/app.component.ts
index becfd00..19a4920 100644
--- a/assets/app/app.component.ts
+++ b/assets/app/app.component.ts
@@ -1,8 +1,11 @@
import { Component } from '@angular/core';
+import { Message } from './messages/message.model';
+import { MessageService } from './messages/message.service';
@Component({
selector: 'my-app',
- templateUrl: './app.component.html'
+ templateUrl: './app.component.html',
+ providers: [MessageService]
})
export class AppComponent {
diff --git a/assets/app/app.module.ts b/assets/app/app.module.ts
index dbef480..b5caed5 100644
--- a/assets/app/app.module.ts
+++ b/assets/app/app.module.ts
@@ -1,13 +1,45 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms'
+import { HttpModule } from '@angular/http'
import { AppComponent } from "./app.component";
+import { MessageComponent } from './messages/message.component';
+import { MessageListComponent } from './messages/message-list.component';
+import { MessageInputComponent } from './messages/message-input.component';
+import { MessagesComponent } from './messages/messages.component';
+import { AuthenticationComponent } from './auth/authentication.component';
+import { HeaderComponent } from './header.component';
+import { routing } from './app.routing';
+import { SigninComponent } from './auth/signin.component';
+import { SignupComponent } from './auth/signup.component';
+import { LogoutComponent } from './auth/logout.component';
+import { AuthService } from './auth/auth.service';
+import { ErrorComponent } from './errors/error.component';
+import { ErrorService } from './errors/error.service';
@NgModule({
declarations: [
- AppComponent
+ AppComponent,
+ MessageComponent,
+ MessageListComponent,
+ MessageInputComponent,
+ MessagesComponent,
+ AuthenticationComponent,
+ HeaderComponent,
+ SigninComponent,
+ SignupComponent,
+ LogoutComponent,
+ ErrorComponent
],
- imports: [BrowserModule],
+ imports: [
+ BrowserModule,
+ FormsModule,
+ routing,
+ ReactiveFormsModule,
+ HttpModule
+ ],
+ providers: [AuthService, ErrorService],
bootstrap: [AppComponent]
})
export class AppModule {
diff --git a/assets/app/app.routing.ts b/assets/app/app.routing.ts
new file mode 100644
index 0000000..c15f928
--- /dev/null
+++ b/assets/app/app.routing.ts
@@ -0,0 +1,12 @@
+import { Routes, RouterModule } from "@angular/router";
+import { MessagesComponent } from "./messages/messages.component";
+import { AuthenticationComponent } from "./auth/authentication.component";
+import { AUTH_ROUTES } from "./auth/auth.routes";
+
+const APP_ROUTES: Routes = [
+ { path: '', redirectTo: '/messages', pathMatch: 'full'},
+ { path: 'messages', component: MessagesComponent },
+ { path: 'auth', component: AuthenticationComponent, children: AUTH_ROUTES }
+];
+
+export const routing = RouterModule.forRoot(APP_ROUTES);
\ No newline at end of file
diff --git a/assets/app/auth/auth.routes.ts b/assets/app/auth/auth.routes.ts
new file mode 100644
index 0000000..f6c5652
--- /dev/null
+++ b/assets/app/auth/auth.routes.ts
@@ -0,0 +1,11 @@
+import { Routes } from '@angular/router';
+import { SignupComponent } from './signup.component';
+import { SigninComponent } from './signin.component';
+import { LogoutComponent } from './logout.component';
+
+export const AUTH_ROUTES: Routes = [
+ { path: '', redirectTo: 'signin', pathMatch: 'full' },
+ { path: 'signup', component: SignupComponent },
+ { path: 'signin', component: SigninComponent },
+ { path: 'logout', component: LogoutComponent }
+];
\ No newline at end of file
diff --git a/assets/app/auth/auth.service.ts b/assets/app/auth/auth.service.ts
new file mode 100644
index 0000000..9f3b3c5
--- /dev/null
+++ b/assets/app/auth/auth.service.ts
@@ -0,0 +1,46 @@
+import { Injectable } from "@angular/core";
+import { Http, Headers, Response } from "@angular/http";
+import 'rxjs/Rx';
+import { Observable } from "rxjs/Observable";
+
+import { User } from "./user.model";
+import { ErrorService } from "../errors/error.service";
+
+
+@Injectable()
+export class AuthService {
+ constructor(private http: Http, private errorService: ErrorService) {}
+
+ signup(user: User) {
+ const body = JSON.stringify(user);
+ const headers = new Headers({'Content-Type': 'application/json'});
+ return this.http.post('http://localhost:3000/user', body, {headers: headers})
+ .map((response: Response) => {
+ console.log(response);
+ return response.json();
+ })
+ .catch((error: Response) => {
+ this.errorService.handleError(error.json());
+ return Observable.throw(error.json());
+ });
+ }
+
+ signin(user: User) {
+ const body = JSON.stringify(user);
+ const headers = new Headers({'Content-Type': 'application/json'});
+ return this.http.post('http://localhost:3000/user/signin', body, {headers: headers})
+ .map((response: Response) => response.json())
+ .catch((error: Response) => {
+ this.errorService.handleError(error.json());
+ return Observable.throw(error.json());
+ });
+ }
+
+ logout() {
+ localStorage.clear();
+ }
+
+ isLoggedIn() {
+ return localStorage.getItem('token') !== null;
+ }
+}
\ No newline at end of file
diff --git a/assets/app/auth/authentication.component.ts b/assets/app/auth/authentication.component.ts
new file mode 100644
index 0000000..e0930aa
--- /dev/null
+++ b/assets/app/auth/authentication.component.ts
@@ -0,0 +1,29 @@
+import { Component } from "@angular/core";
+import { AuthService } from "./auth.service";
+
+@Component({
+ selector: 'app-authentication',
+ template: `
+
+
+
+
+ `
+})
+export class AuthenticationComponent {
+
+ constructor(private authService: AuthService) {}
+
+ isLoggedIn() {
+ return this.authService.isLoggedIn();
+ }
+
+}
\ No newline at end of file
diff --git a/assets/app/auth/logout.component.ts b/assets/app/auth/logout.component.ts
new file mode 100644
index 0000000..49b97e2
--- /dev/null
+++ b/assets/app/auth/logout.component.ts
@@ -0,0 +1,19 @@
+import { Component } from "@angular/core";
+import { AuthService } from "./auth.service";
+import { Router } from "@angular/router";
+
+@Component({
+ selector: 'app-logout',
+ template: `
+
+
+
+ `
+})
+export class LogoutComponent {
+ constructor(private authService: AuthService, private router: Router) {}
+ onLogout() {
+ this.authService.logout();
+ this.router.navigate(['/auth', 'signin']);
+ }
+}
\ No newline at end of file
diff --git a/assets/app/auth/signin.component.html b/assets/app/auth/signin.component.html
new file mode 100644
index 0000000..00b086d
--- /dev/null
+++ b/assets/app/auth/signin.component.html
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/assets/app/auth/signin.component.ts b/assets/app/auth/signin.component.ts
new file mode 100644
index 0000000..cabceb9
--- /dev/null
+++ b/assets/app/auth/signin.component.ts
@@ -0,0 +1,39 @@
+import { Component } from "@angular/core";
+import { FormGroup, FormControl, Validators } from "@angular/forms";
+import { User } from "./user.model";
+import { AuthService } from "./auth.service";
+import { Router } from "@angular/router";
+
+@Component({
+ selector: 'app-signin',
+ templateUrl: './signin.component.html'
+})
+export class SigninComponent {
+ myForm: FormGroup;
+
+ constructor(private authService: AuthService, private router: Router) {}
+
+ onSubmit() {
+ const user = new User(this.myForm.value.email, this.myForm.value.password)
+ this.authService.signin(user)
+ .subscribe(
+ data => {
+ localStorage.setItem('token', data.token);
+ localStorage.setItem('userId', data.userId);
+ this.router.navigateByUrl('/');
+ },
+ error => console.error(error)
+ )
+ this.myForm.reset();
+ }
+
+ ngOnInit() {
+ this.myForm = new FormGroup({
+ email: new FormControl(null, [
+ Validators.required,
+ Validators.email
+ ]),
+ password: new FormControl(null, Validators.required)
+ });
+ }
+}
\ No newline at end of file
diff --git a/assets/app/auth/signup.component.html b/assets/app/auth/signup.component.html
new file mode 100644
index 0000000..8dd4366
--- /dev/null
+++ b/assets/app/auth/signup.component.html
@@ -0,0 +1,21 @@
+
\ No newline at end of file
diff --git a/assets/app/auth/signup.component.ts b/assets/app/auth/signup.component.ts
new file mode 100644
index 0000000..eb5c736
--- /dev/null
+++ b/assets/app/auth/signup.component.ts
@@ -0,0 +1,41 @@
+import { Component, OnInit } from "@angular/core";
+import { FormGroup, FormControl, Validators } from "@angular/forms";
+import { AuthService } from "./auth.service";
+import { User } from "./user.model";
+
+@Component({
+ selector: 'app-signup',
+ templateUrl: './signup.component.html'
+})
+export class SignupComponent implements OnInit {
+ myForm: FormGroup;
+
+ constructor(private authService: AuthService) {}
+
+ onSubmit() {
+ const user = new User(
+ this.myForm.value.email,
+ this.myForm.value.password,
+ this.myForm.value.firstName,
+ this.myForm.value.lastName
+ );
+ this.authService.signup(user)
+ .subscribe(
+ data => console.log(data),
+ error => console.error(error)
+ );
+ this.myForm.reset();
+ }
+
+ ngOnInit() {
+ this.myForm = new FormGroup({
+ firstName: new FormControl(null, Validators.required),
+ lastName: new FormControl(null, Validators.required),
+ email: new FormControl(null, [
+ Validators.required,
+ Validators.email
+ ]),
+ password: new FormControl(null, Validators.required)
+ });
+ }
+}
\ No newline at end of file
diff --git a/assets/app/auth/user.model.ts b/assets/app/auth/user.model.ts
new file mode 100644
index 0000000..c6e2a1f
--- /dev/null
+++ b/assets/app/auth/user.model.ts
@@ -0,0 +1,6 @@
+export class User {
+ constructor(public email: string,
+ public password: string,
+ public firstName?: string,
+ public lastName?: string ) {}
+}
\ No newline at end of file
diff --git a/assets/app/errors/error.component.html b/assets/app/errors/error.component.html
new file mode 100644
index 0000000..a58858d
--- /dev/null
+++ b/assets/app/errors/error.component.html
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/assets/app/errors/error.component.ts b/assets/app/errors/error.component.ts
new file mode 100644
index 0000000..dac5d71
--- /dev/null
+++ b/assets/app/errors/error.component.ts
@@ -0,0 +1,39 @@
+import { Component, OnInit } from "@angular/core";
+import { Error } from "./error.model";
+import { ErrorService } from "./error.service";
+
+@Component({
+ selector: 'app-error',
+ templateUrl: './error.component.html',
+ styles: [
+ `
+ .backdrop {
+ background-color: rgba(0,0,0,0.6);
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100vh;
+ }
+ `
+ ]
+})
+export class ErrorComponent implements OnInit {
+
+ constructor(private errorService: ErrorService) {}
+
+ ngOnInit() {
+ this.errorService.errorOcurred.subscribe(
+ (error: Error) => {
+ this.error = error;
+ this.display = 'block';
+ }
+ );
+ }
+ error: Error;
+ display = 'none';
+
+ onErrorHandled() {
+ this.display = 'none';
+ }
+}
\ No newline at end of file
diff --git a/assets/app/errors/error.model.ts b/assets/app/errors/error.model.ts
new file mode 100644
index 0000000..36aeaf4
--- /dev/null
+++ b/assets/app/errors/error.model.ts
@@ -0,0 +1,3 @@
+export class Error {
+ constructor(public title: string, public message: string) {}
+}
\ No newline at end of file
diff --git a/assets/app/errors/error.service.ts b/assets/app/errors/error.service.ts
new file mode 100644
index 0000000..e1595ca
--- /dev/null
+++ b/assets/app/errors/error.service.ts
@@ -0,0 +1,11 @@
+import { EventEmitter } from "@angular/core";
+import { Error } from "./error.model";
+
+export class ErrorService {
+ errorOcurred = new EventEmitter();
+
+ handleError(error: any) {
+ const errorData = new Error(error.title, error.error.message);
+ this.errorOcurred.emit(errorData);
+ }
+}
\ No newline at end of file
diff --git a/assets/app/header.component.ts b/assets/app/header.component.ts
new file mode 100644
index 0000000..2940875
--- /dev/null
+++ b/assets/app/header.component.ts
@@ -0,0 +1,18 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: 'app-header',
+ template: `
+
+ `
+})
+export class HeaderComponent {
+
+}
\ No newline at end of file
diff --git a/assets/app/messages/message-input.component.html b/assets/app/messages/message-input.component.html
new file mode 100644
index 0000000..470c083
--- /dev/null
+++ b/assets/app/messages/message-input.component.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/assets/app/messages/message-input.component.ts b/assets/app/messages/message-input.component.ts
new file mode 100644
index 0000000..19ef0fe
--- /dev/null
+++ b/assets/app/messages/message-input.component.ts
@@ -0,0 +1,43 @@
+import { Component, OnInit } from "@angular/core";
+import { MessageService } from "./message.service";
+import { Message } from "./message.model";
+import { NgForm } from "@angular/forms";
+
+@Component({
+ selector: 'app-message-input',
+ templateUrl: './message-input.component.html'
+})
+export class MessageInputComponent implements OnInit {
+ message: Message;
+
+ constructor(private messageService: MessageService) {}
+
+ ngOnInit() {
+ this.messageService.messageIsEdit.subscribe(
+ (message: Message) => this.message = message
+ );
+ }
+
+ onSubmit(form: NgForm) {
+ if(this.message) {
+ this.message.content = form.value.content;
+ this.messageService.updateMessage(this.message).subscribe(
+ result => console.log(result)
+ );
+ this.message = null;
+ } else {
+ const message = new Message(form.value.content, 'Joe');
+ this.messageService.addMessage(message)
+ .subscribe(
+ data => console.log(data),
+ error => console.error(error)
+ );
+ }
+ form.resetForm();
+ }
+
+ onClear(form: NgForm) {
+ this.message = null;
+ form.reset();
+ }
+}
\ No newline at end of file
diff --git a/assets/app/messages/message-list.component.ts b/assets/app/messages/message-list.component.ts
new file mode 100644
index 0000000..08b7727
--- /dev/null
+++ b/assets/app/messages/message-list.component.ts
@@ -0,0 +1,31 @@
+import { Component, OnInit } from "@angular/core";
+import { Message } from "./message.model";
+import { MessageService } from "./message.service";
+
+
+@Component({
+ selector: 'app-message-list',
+ template: `
+
+ `
+})
+export class MessageListComponent implements OnInit {
+ messages: Message[] = [];
+
+ constructor(private messageService: MessageService) {}
+
+ ngOnInit() {
+ this.messageService.getMessages()
+ .subscribe(
+ (messages: Message[]) => {
+ this.messages = messages;
+ }
+ );
+ }
+}
\ No newline at end of file
diff --git a/assets/app/messages/message.component.html b/assets/app/messages/message.component.html
new file mode 100644
index 0000000..6088f05
--- /dev/null
+++ b/assets/app/messages/message.component.html
@@ -0,0 +1,15 @@
+
+
+
+ {{ message.content }}
+
+
+
\ No newline at end of file
diff --git a/assets/app/messages/message.component.ts b/assets/app/messages/message.component.ts
new file mode 100644
index 0000000..fb14830
--- /dev/null
+++ b/assets/app/messages/message.component.ts
@@ -0,0 +1,45 @@
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { Message } from './message.model';
+import { MessageService } from './message.service';
+
+@Component({
+ selector: 'app-message',
+ templateUrl: './message.component.html',
+ styles: [
+ `
+ .author {
+ display: inline-block;
+ font-style: italic;
+ font-size: 12px;
+ width: 80%;
+ }
+ .config {
+ display: inline-block;
+ text-align: right;
+ font-size: 12px;
+ width: 19%;
+ }
+ `
+ ]
+})
+export class MessageComponent {
+ @Input() message: Message;
+ @Output() editClicked = new EventEmitter();
+
+ constructor(private messageService: MessageService) {}
+
+ onEdit() {
+ this.messageService.editMessage(this.message);
+ }
+
+ onDelete() {
+ this.messageService.deleteMessage(this.message)
+ .subscribe(
+ result => console.log(result)
+ );
+ }
+
+ belongsToUser() {
+ return localStorage.getItem('userId') == this.message.userId;
+ }
+}
\ No newline at end of file
diff --git a/assets/app/messages/message.model.ts b/assets/app/messages/message.model.ts
new file mode 100644
index 0000000..5904047
--- /dev/null
+++ b/assets/app/messages/message.model.ts
@@ -0,0 +1,13 @@
+export class Message {
+ content: String;
+ username: string;
+ messageId: string;
+ userId: string;
+
+ constructor(content: string, username: string, messageId?: string, userId?: string) {
+ this.content = content;
+ this.username = username;
+ this.messageId = messageId;
+ this.userId = userId;
+ }
+}
\ No newline at end of file
diff --git a/assets/app/messages/message.service.ts b/assets/app/messages/message.service.ts
new file mode 100644
index 0000000..967a4e4
--- /dev/null
+++ b/assets/app/messages/message.service.ts
@@ -0,0 +1,90 @@
+import { Message } from './message.model'
+import { Injectable, EventEmitter } from '@angular/core';
+import 'rxjs/Rx';
+import { Observable } from 'rxjs';
+import { Http, Headers, Response } from '@angular/http';
+import { ErrorService } from '../errors/error.service';
+
+@Injectable()
+export class MessageService {
+ private messages: Message[] = [];
+ messageIsEdit = new EventEmitter();
+
+ constructor(private http: Http, private errorService: ErrorService) {}
+
+ addMessage(message: Message) {
+ const body = JSON.stringify(message);
+ const headers = new Headers({'Content-Type': 'application/json'});
+ const token = localStorage.getItem('token')
+ ? '?token=' + localStorage.getItem('token')
+ : '';
+ return this.http.post('http://localhost:3000/message' + token, body, {headers: headers})
+ .map((response: Response) => {
+ const result = response.json();
+ const message = new Message(
+ result.obj.content,
+ result.obj.user.firstName,
+ result.obj._id,
+ result.obj.user._id);
+ this.messages.push(message);
+ return message;
+ })
+ .catch((error: Response) => {
+ this.errorService.handleError(error.json());
+ return Observable.throw(error.json());
+ });
+ }
+
+ editMessage(message: Message) {
+ this.messageIsEdit.emit(message);
+ }
+
+ updateMessage(message: Message) {
+ const body = JSON.stringify(message);
+ const headers = new Headers({'Content-Type': 'application/json'});
+ const token = localStorage.getItem('token')
+ ? '?token=' + localStorage.getItem('token')
+ : '';
+ return this.http.patch('http://localhost:3000/message/' + message.messageId + token, body, {headers: headers})
+ .map((response: Response) => response.json())
+ .catch((error: Response) => {
+ this.errorService.handleError(error.json());
+ return Observable.throw(error.json());
+ });
+ }
+
+ getMessages() {
+ return this.http.get('http://localhost:3000/message')
+ .map((response: Response) => {
+ const messages = response.json().obj;
+ let transformedMessages: Message[] = [];
+ for (let message of messages) {
+ transformedMessages.push(new Message(
+ message.content,
+ message.user.firstName,
+ message._id,
+ message.user._id)
+ );
+ }
+ this.messages = transformedMessages;
+ return transformedMessages
+ })
+ .catch((error: Response) => {
+ this.errorService.handleError(error.json());
+ return Observable.throw(error.json());
+ });
+ }
+
+ deleteMessage(message: Message) {
+ this.messages.splice(this.messages.indexOf(message), 1);
+ const token = localStorage.getItem('token')
+ ? '?token=' + localStorage.getItem('token')
+ : '';
+ return this.http.delete('http://localhost:3000/message/' + message.messageId + token)
+ .map((response: Response) => response.json())
+ .catch((error: Response) => {
+ this.errorService.handleError(error.json());
+ return Observable.throw(error.json());
+ });
+ }
+}
\ No newline at end of file
diff --git a/assets/app/messages/messages.component.ts b/assets/app/messages/messages.component.ts
new file mode 100644
index 0000000..206c2b9
--- /dev/null
+++ b/assets/app/messages/messages.component.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+
+
+@Component({
+ selector: 'app-messages',
+ template: `
+
+ `
+})
+export class MessagesComponent {
+
+}
\ No newline at end of file
diff --git a/models/message.js b/models/message.js
new file mode 100644
index 0000000..4dd79c8
--- /dev/null
+++ b/models/message.js
@@ -0,0 +1,18 @@
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var User = require('./user');
+
+var schema = new Schema({
+ content: {type: String, required: true},
+ user: {type: Schema.Types.ObjectId, ref: 'User'}
+});
+
+schema.post('remove', function(message) {
+ User.findById(message.user, function(err, user) {
+ user.messages.pull(message._id);
+ user.save();
+ });
+});
+
+module.exports = mongoose.model('Message', schema);
\ No newline at end of file
diff --git a/models/user.js b/models/user.js
new file mode 100644
index 0000000..11487fb
--- /dev/null
+++ b/models/user.js
@@ -0,0 +1,15 @@
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+var mongooseUniqueValidator = require('mongoose-unique-validator');
+
+var schema = new Schema({
+ firstName: {type: String, required: true},
+ lastName: {type: String, required: true},
+ password: {type: String, required: true},
+ email: {type: String, required: true},
+ messages: [{type: Schema.Types.ObjectId, ref: 'Message'}]
+});
+
+schema.plugin(mongooseUniqueValidator);
+
+module.exports = mongoose.model('User', schema);
\ No newline at end of file
diff --git a/package.json b/package.json
index 543a131..02bdd1d 100644
--- a/package.json
+++ b/package.json
@@ -20,17 +20,21 @@
"@angular/platform-server": "^4.0.0",
"@angular/router": "^4.0.0",
"@angular/upgrade": "^4.0.0",
+ "bcryptjs": "^2.4.3",
"body-parser": "~1.15.2",
"cookie-parser": "~1.4.3",
+ "core-js": "^2.4.1",
"debug": "~2.2.0",
"express": "~4.14.0",
"hbs": "~3.1.0",
+ "jsonwebtoken": "^8.0.1",
+ "mongoose": "^4.11.11",
+ "mongoose-unique-validator": "^1.0.6",
"morgan": "~1.6.1",
"reflect-metadata": "^0.1.3",
- "core-js": "^2.4.1",
"rxjs": "^5.2.0",
- "zone.js": "^0.8.5",
- "serve-favicon": "~2.3.0"
+ "serve-favicon": "~2.3.0",
+ "zone.js": "^0.8.5"
},
"devDependencies": {
"@types/core-js": "0.9.36",
diff --git a/routes/app.js b/routes/app.js
index 5c71bdb..b346d11 100644
--- a/routes/app.js
+++ b/routes/app.js
@@ -5,13 +5,4 @@ router.get('/', function (req, res, next) {
res.render('index');
});
-router.get('/message/:msg', function (req, res, next) {
- res.render('node', {message: req.params.msg});
-});
-
-router.post('/message', function(req, res, next) {
- var message = req.body.message;
- res.redirect('/message/' + message);
-});
-
module.exports = router;
diff --git a/routes/messages.js b/routes/messages.js
new file mode 100644
index 0000000..c129cbc
--- /dev/null
+++ b/routes/messages.js
@@ -0,0 +1,142 @@
+var express = require('express');
+var router = express.Router();
+var jwt = require('jsonwebtoken');
+
+var Message = require('../models/message');
+var User = require('../models/user');
+
+router.get('/', function(req, res, next) {
+ Message.find()
+ .populate('user', 'firstName')
+ .exec(function(err, messages) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+
+ res.status(201).json({
+ message: 'Success!',
+ obj: messages
+ });
+ });
+});
+
+router.use('/', function(req, res, next) {
+ jwt.verify(req.query.token, 'secret', function(err, decoded) {
+ if(err) {
+ return res.status(401).json({
+ title: 'Not Authenticated',
+ error: err
+ });
+ }
+ next();
+ });
+});
+
+router.post('/', function(req, res, next) {
+ var decoded = jwt.decode(req.query.token);
+ User.findById(decoded.user._id, function(err, user) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+ var message = new Message({
+ content: req.body.content,
+ user: user._id
+ });
+
+ message.save(function(err, result) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+ user.messages.push(result);
+ user.save();
+ res.status(201).json({
+ message: 'Saved message',
+ obj: result
+ });
+ });
+ });
+});
+
+router.patch('/:id', function(req, res, next) {
+ var decoded = jwt.decode(req.query.token);
+ Message.findById(req.params.id, function(err, message) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+ if(!message) {
+ return res.status(500).json({
+ title: 'No message found!',
+ error: {message: 'Message not found!'}
+ });
+ }
+ if(message.user != decoded.user._id) {
+ return res.status(401).json({
+ title: 'Not Authenticated',
+ error: {message: 'Users do not match'}
+ });
+ }
+ message.content = req.body.content;
+ message.save(function(err, result) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+ res.status(200).json({
+ message: 'Updated message',
+ obj: result
+ });
+ });
+ });
+});
+
+router.delete('/:id', function(req, res, next) {
+ var decoded = jwt.decode(req.query.token);
+ Message.findById(req.params.id, function(err, message) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+ if(!message) {
+ return res.status(500).json({
+ title: 'No message found!',
+ error: {message: 'Message not found!'}
+ });
+ }
+ if(message.user != decoded.user._id) {
+ return res.status(401).json({
+ title: 'Not Authenticated',
+ error: {message: 'Users do not match'}
+ });
+ }
+ message.remove(function(err, result) {
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ error: err
+ });
+ }
+ res.status(200).json({
+ message: 'Deleted message',
+ obj: result
+ });
+ });
+ });
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/routes/users.js b/routes/users.js
new file mode 100644
index 0000000..8e8baf2
--- /dev/null
+++ b/routes/users.js
@@ -0,0 +1,60 @@
+var express = require('express');
+var router = express.Router();
+var bcrypt = require('bcryptjs');
+var jwt = require('jsonwebtoken');
+
+var User = require('../models/user');
+
+router.post('/', function(req, res, next) {
+ var user = new User({
+ firstName: req.body.firstName,
+ lastName: req.body.lastName,
+ password: bcrypt.hashSync(req.body.password, 10),
+ email: req.body.email,
+ });
+ user.save(function(err, result){
+ if(err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ errors: err
+ });
+ }
+ res.status(201).json({
+ message: 'User created',
+ obj: result
+ });
+ });
+});
+
+router.post('/signin', function(req, res, next) {
+ User.findOne({email: req.body.email}, function(err, user){
+ if (err) {
+ return res.status(500).json({
+ title: 'An error occurred',
+ errors: err
+ });
+ }
+ if (!user) {
+ return res.status(401).json({
+ title: 'Login failed',
+ errors: { message: 'Invalid login credentials'}
+ });
+ }
+ if(!bcrypt.compareSync(req.body.password, user.password)) {
+ return res.status(401).json({
+ title: 'Login failed',
+ errors: { message: 'Invalid login credentials'}
+ });
+ }
+
+ //gut
+ var token = jwt.sign({user: user}, 'secret', {expiresIn: 7200});
+ res.status(200).json({
+ message: 'Successfully logged in',
+ token: token,
+ userId: user._id
+ });
+ });
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/views/node.hbs b/views/node.hbs
deleted file mode 100644
index 1051e25..0000000
--- a/views/node.hbs
+++ /dev/null
@@ -1,6 +0,0 @@
-A NodeJS View
-{{ message }}
-
\ No newline at end of file