-
+
Unknown sample number
diff --git a/src/app/sample/sample.component.ts b/src/app/sample/sample.component.ts
index 5f68668..985ea69 100644
--- a/src/app/sample/sample.component.ts
+++ b/src/app/sample/sample.component.ts
@@ -27,7 +27,7 @@ import {Observable} from 'rxjs';
// TODO: material properties, color (in material and sample (not required))
-// TODO: API $in Regex
+// TODO: device autocomplete
@Component({
selector: 'app-sample',
diff --git a/src/app/services/login.service.ts b/src/app/services/login.service.ts
index 6de63eb..6f66d51 100644
--- a/src/app/services/login.service.ts
+++ b/src/app/services/login.service.ts
@@ -9,7 +9,17 @@ import {Observable} from 'rxjs';
})
export class LoginService implements CanActivate {
- private maintainPaths = ['templates'];
+ private pathPermissions = [
+ {path: 'templates', permission: 'maintain'},
+ {path: 'users', permission: 'admin'}
+ ];
+ readonly levels = [
+ 'read',
+ 'write',
+ 'maintain',
+ 'dev',
+ 'admin'
+ ];
private loggedIn;
private level;
@@ -23,9 +33,28 @@ export class LoginService implements CanActivate {
login(username = '', password = '') {
return new Promise(resolve => {
- if (username !== '') {
- this.storage.set('basicAuth', btoa(username + ':' + password));
+ console.log(username);
+ console.log(password);
+ if (username !== '' || password !== '') { // some credentials given
+ let credentials: string[];
+ const credentialString: string = this.storage.get('basicAuth');
+ if (credentialString) { // found stored credentials
+ credentials = atob(credentialString).split(':');
+ }
+ else {
+ credentials = ['', ''];
+ }
+ if (username !== '' && password !== '') { // all credentials given
+ this.storage.set('basicAuth', btoa(username + ':' + password));
+ }
+ else if (username !== '') { // username given
+ this.storage.set('basicAuth', btoa(username + ':' + credentials[1]));
+ }
+ else if (password !== '') { // password given
+ this.storage.set('basicAuth', btoa(credentials[0] + ':' + password));
+ }
}
+ console.log(this.storage.get('basicAuth'));
this.api.get('/authorized', (data: any, error) => {
if (!error) {
if (data.status === 'Authorization successful') {
@@ -53,8 +82,8 @@ export class LoginService implements CanActivate {
canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable
{
return new Observable(observer => {
- const isMaintainPath = this.maintainPaths.indexOf(route.url[0].path) >= 0;
- if (!isMaintainPath || (isMaintainPath && this.isMaintain)) {
+ const pathPermission = this.pathPermissions.find(e => e.path.indexOf(route.url[0].path) >= 0);
+ if (!pathPermission || this.is(pathPermission.permission)) { // check if level is permitted for path
if (this.loggedIn === undefined) {
this.login().then(res => {
observer.next(res as any);
@@ -77,8 +106,8 @@ export class LoginService implements CanActivate {
return this.loggedIn;
}
- get isMaintain() {
- return this.level === 'maintain' || this.level === 'admin';
+ is(level) {
+ return this.levels.indexOf(this.level) >= this.levels.indexOf(level);
}
get username() {
diff --git a/src/app/services/validation.service.ts b/src/app/services/validation.service.ts
index 8dd273a..a58ec72 100644
--- a/src/app/services/validation.service.ts
+++ b/src/app/services/validation.service.ts
@@ -66,10 +66,16 @@ export class ValidationService {
return {ok: true, error: ''};
}
- string(data) {
- const {ignore, error} = Joi.string().max(128).allow('').validate(data);
+ string(data, option = null) {
+ let validator = Joi.string().max(128).allow('');
+ let errorMsg = 'must contain max 128 characters';
+ if (option === 'alphanum') {
+ validator = validator.alphanum();
+ errorMsg = 'must contain max 128 alphanumerical characters';
+ }
+ const {ignore, error} = validator.validate(data);
if (error) {
- return {ok: false, error: 'must contain max 128 characters'};
+ return {ok: false, error: errorMsg};
}
return {ok: true, error: ''};
}
@@ -122,6 +128,13 @@ export class ValidationService {
return {ok: true, error: ''};
}
+ equal(data, compare) {
+ if (data !== compare) {
+ return {ok: false, error: `must be equal`};
+ }
+ return {ok: true, error: ''};
+ }
+
parameterName(data) {
const {ignore, error} = Joi.string()
.max(128)
diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html
new file mode 100644
index 0000000..8e73ba1
--- /dev/null
+++ b/src/app/settings/settings.component.html
@@ -0,0 +1,45 @@
+Settings
+
+
+
+
+Change password
+
+
+
diff --git a/src/app/settings/settings.component.scss b/src/app/settings/settings.component.scss
new file mode 100644
index 0000000..3651625
--- /dev/null
+++ b/src/app/settings/settings.component.scss
@@ -0,0 +1,7 @@
+.pass-heading {
+ margin-top: 40px;
+}
+
+.message {
+ margin-left: 20px;
+}
diff --git a/src/app/settings/settings.component.spec.ts b/src/app/settings/settings.component.spec.ts
new file mode 100644
index 0000000..91588f3
--- /dev/null
+++ b/src/app/settings/settings.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SettingsComponent } from './settings.component';
+
+describe('SettingsComponent', () => {
+ let component: SettingsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SettingsComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SettingsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/settings/settings.component.ts b/src/app/settings/settings.component.ts
new file mode 100644
index 0000000..313d727
--- /dev/null
+++ b/src/app/settings/settings.component.ts
@@ -0,0 +1,68 @@
+import { Component, OnInit } from '@angular/core';
+import {ApiService} from '../services/api.service';
+import {UserModel} from '../models/user.model';
+import {Router} from '@angular/router';
+import {LoginService} from '../services/login.service';
+
+
+@Component({
+ selector: 'app-settings',
+ templateUrl: './settings.component.html',
+ styleUrls: ['./settings.component.scss']
+})
+export class SettingsComponent implements OnInit {
+
+ user: UserModel = new UserModel();
+ password = '';
+ messageUser = '';
+ messagePass = '';
+
+ constructor(
+ private api: ApiService,
+ private login: LoginService,
+ private router: Router
+ ) { }
+
+ ngOnInit(): void {
+ this.api.get('/user', data => {
+ this.user.deserialize(data);
+ });
+ }
+
+ saveUser() {
+ this.api.put('/user', this.user.sendFormat(), (data, err) => {
+ if (err) {
+ this.messageUser = err.error.status;
+ }
+ else {
+ this.login.login(data.name).then(res => {
+ if (res) {
+ this.router.navigate(['/samples']);
+ }
+ else {
+ this.messageUser = 'request not successful, try again';
+ }
+ });
+ }
+ });
+ }
+
+ savePass() {
+ this.api.put('/user', {pass: this.password}, (ignore, err) => {
+ if (err) {
+ this.messagePass = err.error.status;
+ }
+ else {
+ this.login.login('', this.password).then(res => {
+ if (res) {
+ this.router.navigate(['/samples']);
+ }
+ else {
+ this.messagePass = 'request not successful, try again';
+ }
+ });
+ }
+ });
+ }
+
+}
diff --git a/src/app/templates/templates.component.scss b/src/app/templates/templates.component.scss
index eb79c15..ede71e8 100644
--- a/src/app/templates/templates.component.scss
+++ b/src/app/templates/templates.component.scss
@@ -38,7 +38,3 @@
}
}
}
-
-.clickable {
- cursor: pointer;
-}
diff --git a/src/app/users/users.component.html b/src/app/users/users.component.html
new file mode 100644
index 0000000..b176428
--- /dev/null
+++ b/src/app/users/users.component.html
@@ -0,0 +1,94 @@
+Users
+
+New user
+
+
+
+
+
+ Name |
+ Email |
+ Level |
+ Location |
+ Device |
+ |
+
+
+
+
+ {{user.name}} |
+ {{user.email}} |
+ {{user.level}} |
+ {{user.location}} |
+ {{user.device_name}} |
+ |
+
+
+
+
+ {{nameInput.errors.failure}}
+ Cannot be empty
+
+ |
+
+
+ Invalid email
+ Cannot be empty
+
+ |
+
+
+
+
+ |
+
+
+ {{locationInput.errors.failure}}
+ Cannot be empty
+
+ |
+
+
+ {{deviceInput.errors.failure}}
+
+ |
+ Save |
+
+
+
diff --git a/src/app/users/users.component.scss b/src/app/users/users.component.scss
new file mode 100644
index 0000000..9ba4fcf
--- /dev/null
+++ b/src/app/users/users.component.scss
@@ -0,0 +1,3 @@
+::ng-deep td .error-messages {
+ position: absolute;
+}
diff --git a/src/app/users/users.component.spec.ts b/src/app/users/users.component.spec.ts
new file mode 100644
index 0000000..909b5ba
--- /dev/null
+++ b/src/app/users/users.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UsersComponent } from './users.component';
+
+describe('UsersComponent', () => {
+ let component: UsersComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ UsersComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UsersComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/users/users.component.ts b/src/app/users/users.component.ts
new file mode 100644
index 0000000..d80817b
--- /dev/null
+++ b/src/app/users/users.component.ts
@@ -0,0 +1,47 @@
+import { Component, OnInit } from '@angular/core';
+import {ApiService} from '../services/api.service';
+import {UserModel} from '../models/user.model';
+import {LoginService} from '../services/login.service';
+
+
+@Component({
+ selector: 'app-users',
+ templateUrl: './users.component.html',
+ styleUrls: ['./users.component.scss']
+})
+export class UsersComponent implements OnInit {
+
+ users: UserModel[] = [];
+ newUser: UserModel | null = null;
+ newUserPass = '';
+
+ constructor(
+ private api: ApiService,
+ public login: LoginService
+ ) { }
+
+ ngOnInit(): void {
+ this.api.get('/users', data => {
+ this.users = data.map(e => new UserModel().deserialize(e));
+ });
+ }
+
+ saveUser(user: UserModel) {
+ this.api.put('/user/' + user.origName, user.sendFormat('admin'), data => {
+ user.deserialize(data);
+ user.edit = false;
+ });
+ }
+
+ saveNewUser() {
+ this.api.post('/user/new', {...this.newUser.sendFormat('admin'), pass: this.newUserPass}, data => {
+ this.newUser = null;
+ this.users.push(new UserModel().deserialize(data));
+ });
+ }
+
+ addNewUser() {
+ this.newUser = this.newUser ? null : new UserModel();
+ }
+
+}
diff --git a/src/styles.scss b/src/styles.scss
index ae773e1..a0f6fd5 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -19,3 +19,7 @@ button::-moz-focus-inner {
.supergraphic {
background-image: url("assets/imgs/supergraphic.svg");
}
+
+.clickable {
+ cursor: pointer;
+}