diff --git a/api/auth.go b/api/auth.go index f420be6..d70aa81 100644 --- a/api/auth.go +++ b/api/auth.go @@ -3,19 +3,39 @@ package api import ( "encoding/json" "github.com/Sirupsen/logrus" - "github.com/kataras/go-sessions" "github.com/simon987/task_tracker/storage" ) +const MaxUsernameLength = 16 + type LoginRequest struct { - Username []byte - Password []byte + Username string `json:"username"` + Password string `json:"password"` } type LoginResponse struct { - Ok bool - Message string - Manager *storage.Manager + Ok bool `json:"ok"` + Message string `json:"message,omitempty"` + Manager *storage.Manager `json:"manager"` +} + +type RegisterRequest struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type AccountDetails struct { + LoggedIn bool `json:"logged_in"` + Manager *storage.Manager `json:"manager,omitempty"` +} + +func (r *RegisterRequest) isValid() bool { + return len(r.Username) <= MaxUsernameLength +} + +type RegisterResponse struct { + Ok bool `json:"ok"` + Message string `json:"message,omitempty"` } func (api *WebAPI) Login(r *Request) { @@ -31,10 +51,10 @@ func (api *WebAPI) Login(r *Request) { return } - manager, err := api.Database.ValidateCredentials(req.Username, req.Password) + manager, err := api.Database.ValidateCredentials([]byte(req.Username), []byte(req.Password)) if err != nil { logrus.WithError(err).WithFields(logrus.Fields{ - "username": string(manager.Username), + "username": req.Username, }).Warning("Login attempt") r.Json(LoginResponse{ @@ -44,10 +64,88 @@ func (api *WebAPI) Login(r *Request) { return } - sess := sessions.StartFasthttp(r.Ctx) + sess := api.Session.StartFasthttp(r.Ctx) sess.Set("manager", manager) + logrus.Debug("SET") + logrus.Debug(sess.ID()) + logrus.Debug(manager) + + r.OkJson(LoginResponse{ + Manager: manager, + Ok: true, + }) + logrus.WithFields(logrus.Fields{ "username": string(manager.Username), }).Info("Logged in") } + +func (api *WebAPI) Register(r *Request) { + + req := &RegisterRequest{} + err := json.Unmarshal(r.Ctx.Request.Body(), req) + + if err != nil { + r.Json(LoginResponse{ + Ok: false, + Message: "Could not parse request", + }, 400) + return + } + + if !req.isValid() { + r.Json(LoginResponse{ + Ok: false, + Message: "Invalid register request", + }, 400) + return + } + + manager := &storage.Manager{ + Username: string(req.Username), + } + + err = api.Database.SaveManager(manager, []byte(req.Password)) + if err != nil { + logrus.WithError(err).WithFields(logrus.Fields{ + "username": string(manager.Username), + }).Warning("Register attempt") + + r.Json(LoginResponse{ + Ok: false, + Message: err.Error(), + }, 400) + return + } + + sess := api.Session.StartFasthttp(r.Ctx) + sess.Set("manager", manager) + + r.OkJson(RegisterResponse{ + Ok: true, + }) + + logrus.WithFields(logrus.Fields{ + "username": string(manager.Username), + }).Info("Registered") +} + +func (api *WebAPI) AccountDetails(r *Request) { + + sess := api.Session.StartFasthttp(r.Ctx) + manager := sess.Get("manager") + logrus.Debug("GET") + logrus.Debug(sess.ID()) + + if manager == nil { + r.OkJson(AccountDetails{ + LoggedIn: false, + }) + } else { + r.OkJson(AccountDetails{ + LoggedIn: true, + Manager: manager.(*storage.Manager), + }) + } +} diff --git a/api/log.go b/api/log.go index 612158d..5761420 100644 --- a/api/log.go +++ b/api/log.go @@ -39,6 +39,10 @@ func (e *LogRequest) Time() time.Time { func LogRequestMiddleware(h RequestHandler) fasthttp.RequestHandler { return fasthttp.RequestHandler(func(ctx *fasthttp.RequestCtx) { + ctx.Response.Header.Add("Access-Control-Allow-Headers", "Content-Type") + ctx.Response.Header.Add("Access-Control-Allow-Methods", "GET, POST, OPTION") + ctx.Response.Header.Add("Access-Control-Allow-Origin", "*") + logrus.WithFields(logrus.Fields{ "path": string(ctx.Path()), "header": ctx.Request.Header.String(), diff --git a/api/main.go b/api/main.go index da68084..f5bf5fb 100644 --- a/api/main.go +++ b/api/main.go @@ -14,7 +14,8 @@ type WebAPI struct { server *fasthttp.Server router *fasthttprouter.Router Database *storage.Database - SessionConfig *sessions.Config + SessionConfig sessions.Config + Session *sessions.Sessions } type Info struct { @@ -38,11 +39,15 @@ func New() *WebAPI { api.router = &fasthttprouter.Router{} - api.SessionConfig = &sessions.Config{ - Cookie: config.Cfg.SessionCookieName, - Expires: config.Cfg.SessionCookieExpiration, + api.SessionConfig = sessions.Config{ + Cookie: config.Cfg.SessionCookieName, + Expires: config.Cfg.SessionCookieExpiration, + CookieSecureTLS: false, + DisableSubdomainPersistence: false, } + api.Session = sessions.New(api.SessionConfig) + api.server = &fasthttp.Server{ Handler: api.router.Handler, Name: info.Name, @@ -76,6 +81,10 @@ func New() *WebAPI { api.router.POST("/logs", LogRequestMiddleware(api.GetLog)) + api.router.POST("/register", LogRequestMiddleware(api.Register)) + api.router.POST("/login", LogRequestMiddleware(api.Login)) + api.router.GET("/account", LogRequestMiddleware(api.AccountDetails)) + api.router.NotFound = func(ctx *fasthttp.RequestCtx) { if ctx.Request.Header.IsOptions() { diff --git a/config.yml b/config.yml index a32e89a..a5de15b 100755 --- a/config.yml +++ b/config.yml @@ -15,3 +15,7 @@ git: log: # panic, fatal, error, warn, info, debug, trace level: "trace" + +session: + cookie_name: "tt" + expiration: "25m" diff --git a/schema.sql b/schema.sql index 1a7c13c..674ca07 100755 --- a/schema.sql +++ b/schema.sql @@ -76,8 +76,8 @@ CREATE TABLE log_entry CREATE TABLE manager ( id SERIAL PRIMARY KEY, - username TEXT, - password TEXT, + username TEXT UNIQUE, + password BYTEA, website_admin BOOLEAN ); diff --git a/storage/auth.go b/storage/auth.go index efcef74..2613415 100644 --- a/storage/auth.go +++ b/storage/auth.go @@ -62,13 +62,14 @@ func (database *Database) SaveManager(manager *Manager, password []byte) error { hash := crypto.SHA512.New() hash.Write(password) + hash.Write([]byte(manager.Username)) hashedPassword := hash.Sum(nil) row := db.QueryRow(`INSERT INTO manager (username, password, website_admin) VALUES ($1,$2,$3) RETURNING ID`, manager.Username, hashedPassword, manager.WebsiteAdmin) - err := row.Scan(manager.Id) + err := row.Scan(&manager.Id) if err != nil { logrus.WithError(err).WithFields(logrus.Fields{ "username": manager, @@ -100,22 +101,23 @@ func (database *Database) UpdateManager(manager *Manager) { }).Warning("Database.UpdateManager UPDATE") } -func (database *Database) UpdateManagerPassword(id int64, newPassword []byte) { +func (database *Database) UpdateManagerPassword(manager *Manager, newPassword []byte) { hash := crypto.SHA512.New() + hash.Write([]byte(manager.Username)) hash.Write(newPassword) hashedPassword := hash.Sum(nil) db := database.getDB() res, err := db.Exec(`UPDATE manager SET password=$1 WHERE id=$2`, - hashedPassword, id) + hashedPassword, manager.Id) handleErr(err) rowsAffected, _ := res.RowsAffected() logrus.WithError(err).WithFields(logrus.Fields{ "rowsAffected": rowsAffected, - "id": id, + "id": manager.Id, }).Warning("Database.UpdateManagerPassword UPDATE") } diff --git a/storage/project.go b/storage/project.go index 1eb6c98..a8427c7 100644 --- a/storage/project.go +++ b/storage/project.go @@ -132,7 +132,7 @@ func (database *Database) UpdateProject(project *Project) error { } func (database Database) GetAllProjects() *[]Project { - var projects []Project + projects := make([]Project, 0) db := database.getDB() rows, err := db.Query(`SELECT diff --git a/test/config.yml b/test/config.yml index a9a6c48..0324e87 100644 --- a/test/config.yml +++ b/test/config.yml @@ -15,5 +15,5 @@ log: level: "trace" session: - cookie_name: "tt" + cookie_name: "tt_test" expiration: "25m" \ No newline at end of file diff --git a/web/angular/package-lock.json b/web/angular/package-lock.json index db8e5e8..f197231 100644 --- a/web/angular/package-lock.json +++ b/web/angular/package-lock.json @@ -1262,7 +1262,6 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, - "optional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -2516,8 +2515,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "constants-browserify": { "version": "1.0.0", @@ -2919,8 +2917,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true, - "optional": true + "dev": true }, "depd": { "version": "1.1.2", @@ -3995,8 +3992,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -4017,14 +4013,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4039,20 +4033,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -4169,8 +4160,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -4182,7 +4172,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4197,7 +4186,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4205,14 +4193,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4231,7 +4217,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4312,8 +4297,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4325,7 +4309,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4411,8 +4394,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4448,7 +4430,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4468,7 +4449,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4512,14 +4492,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -4528,7 +4506,6 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -4541,7 +4518,6 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, - "optional": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -4579,8 +4555,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "3.0.0", @@ -4805,8 +4780,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true, - "optional": true + "dev": true }, "has-value": { "version": "1.0.0", @@ -5562,8 +5536,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true, - "optional": true + "dev": true }, "is-windows": { "version": "1.0.2", @@ -6246,7 +6219,6 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -6259,8 +6231,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "optional": true + "dev": true } } }, @@ -6534,8 +6505,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "optional": true + "dev": true }, "map-visit": { "version": "1.0.0", @@ -7167,7 +7137,6 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, - "optional": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -8259,7 +8228,6 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, - "optional": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", @@ -8271,7 +8239,6 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", @@ -8282,8 +8249,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "optional": true + "dev": true } } }, @@ -8292,7 +8258,6 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, - "optional": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" @@ -8303,7 +8268,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, - "optional": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" @@ -8314,7 +8278,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, - "optional": true, "requires": { "pinkie-promise": "^2.0.0" } @@ -9605,7 +9568,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, - "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -10936,7 +10898,6 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, - "optional": true, "requires": { "string-width": "^1.0.2 || 2" } diff --git a/web/angular/src/app/account-details/account-details.component.css b/web/angular/src/app/account-details/account-details.component.css new file mode 100644 index 0000000..e69de29 diff --git a/web/angular/src/app/account-details/account-details.component.html b/web/angular/src/app/account-details/account-details.component.html new file mode 100644 index 0000000..342f05c --- /dev/null +++ b/web/angular/src/app/account-details/account-details.component.html @@ -0,0 +1,3 @@ +
+    {{authService.account | json}}
+
diff --git a/web/angular/src/app/account-details/account-details.component.ts b/web/angular/src/app/account-details/account-details.component.ts new file mode 100644 index 0000000..0f9ef4e --- /dev/null +++ b/web/angular/src/app/account-details/account-details.component.ts @@ -0,0 +1,17 @@ +import {Component, OnInit} from '@angular/core'; +import {AuthService} from "../auth.service"; + +@Component({ + selector: 'app-account-details', + templateUrl: './account-details.component.html', + styleUrls: ['./account-details.component.css'] +}) +export class AccountDetailsComponent implements OnInit { + + constructor(private authService: AuthService) { + } + + ngOnInit() { + } + +} diff --git a/web/angular/src/app/api.service.ts b/web/angular/src/app/api.service.ts index 2e805e1..24deacd 100755 --- a/web/angular/src/app/api.service.ts +++ b/web/angular/src/app/api.service.ts @@ -1,11 +1,16 @@ import {Injectable} from '@angular/core'; import {HttpClient} from "@angular/common/http"; import {Project} from "./models/project"; +import {Credentials} from "./models/credentials"; @Injectable() export class ApiService { - private url: string = "http://localhost:42901"; + private url: string = "http://localhost/api"; + private options: { + withCredentials: true, + responseType: "json" + }; constructor( private http: HttpClient, @@ -13,22 +18,36 @@ export class ApiService { } getLogs() { - return this.http.post(this.url + "/logs", "{\"level\":6, \"since\":1}"); + return this.http.post(this.url + "/logs", "{\"level\":6, \"since\":1}", this.options); } getProjects() { - return this.http.get(this.url + "/project/list") + return this.http.get(this.url + "/project/list", this.options) } getProject(id: number) { - return this.http.get(this.url + "/project/get/" + id) + return this.http.get(this.url + "/project/get/" + id, this.options) } createProject(project: Project) { - return this.http.post(this.url + "/project/create", project) + return this.http.post(this.url + "/project/create", project, this.options) } updateProject(project: Project) { - return this.http.post(this.url + "/project/update/" + project.id, project) + return this.http.post(this.url + "/project/update/" + project.id, project, this.options) } + + register(credentials: Credentials) { + return this.http.post(this.url + "/register", credentials, this.options) + } + + login(credentials: Credentials) { + return this.http.post(this.url + "/login", credentials, this.options) + } + + getAccountDetails() { + return this.http.get(this.url + "/account", this.options) + } + + } diff --git a/web/angular/src/app/app-routing.module.ts b/web/angular/src/app/app-routing.module.ts index 8195dad..7989baa 100755 --- a/web/angular/src/app/app-routing.module.ts +++ b/web/angular/src/app/app-routing.module.ts @@ -9,12 +9,12 @@ import {Title} from "@angular/platform-browser"; import {filter} from "rxjs/operators"; import {TranslateService} from "@ngx-translate/core"; import {LoginComponent} from "./login/login.component"; -import {CreateAccountComponent} from "./create-account/create-account.component"; +import {AccountDetailsComponent} from "./account-details/account-details.component"; const routes: Routes = [ {path: "log", component: LogsComponent}, {path: "login", component: LoginComponent}, - {path: "new_account", component: CreateAccountComponent}, + {path: "account", component: AccountDetailsComponent}, {path: "projects", component: ProjectListComponent}, {path: "project/:id", component: ProjectDashboardComponent}, {path: "project/:id/update", component: UpdateProjectComponent}, diff --git a/web/angular/src/app/app.component.html b/web/angular/src/app/app.component.html index 5130957..2d6ebad 100755 --- a/web/angular/src/app/app.component.html +++ b/web/angular/src/app/app.component.html @@ -4,6 +4,8 @@ + diff --git a/web/angular/src/app/app.module.ts b/web/angular/src/app/app.module.ts index a9609dc..17db517 100755 --- a/web/angular/src/app/app.module.ts +++ b/web/angular/src/app/app.module.ts @@ -19,12 +19,14 @@ import { MatMenuModule, MatPaginatorIntl, MatPaginatorModule, + MatProgressBarModule, MatSelectModule, MatSliderModule, MatSlideToggleModule, MatSnackBarModule, MatSortModule, MatTableModule, + MatTabsModule, MatToolbarModule, MatTreeModule } from "@angular/material"; @@ -41,7 +43,7 @@ import {TranslateLoader, TranslateModule, TranslateService} from "@ngx-translate import {TranslateHttpLoader} from "@ngx-translate/http-loader"; import {TranslatedPaginator} from "./TranslatedPaginatorConfiguration"; import {LoginComponent} from './login/login.component'; -import {CreateAccountComponent} from './create-account/create-account.component'; +import {AccountDetailsComponent} from './account-details/account-details.component'; export function createTranslateLoader(http: HttpClient) { @@ -59,7 +61,7 @@ export function createTranslateLoader(http: HttpClient) { UpdateProjectComponent, SnackBarComponent, LoginComponent, - CreateAccountComponent, + AccountDetailsComponent, ], imports: [ BrowserModule, @@ -94,7 +96,9 @@ export function createTranslateLoader(http: HttpClient) { } } ), - MatSelectModule + MatSelectModule, + MatProgressBarModule, + MatTabsModule ], exports: [], diff --git a/web/angular/src/app/create-account/create-account.component.css b/web/angular/src/app/create-account/create-account.component.css deleted file mode 100644 index bc76a27..0000000 --- a/web/angular/src/app/create-account/create-account.component.css +++ /dev/null @@ -1,3 +0,0 @@ -mat-form-field { - width: 100%; -} diff --git a/web/angular/src/app/create-account/create-account.component.html b/web/angular/src/app/create-account/create-account.component.html deleted file mode 100644 index eb0cb14..0000000 --- a/web/angular/src/app/create-account/create-account.component.html +++ /dev/null @@ -1,30 +0,0 @@ -
- - {{"create_account.title" | translate}} - -
- - {{"login.username" | translate}} - {{credentials.username?.length || 0}}/16 - - - - - {{ "login.password" | translate}} - - - - - {{ "login.repeat_password" | translate}} - - -
-
- - - -
-
diff --git a/web/angular/src/app/create-account/create-account.component.ts b/web/angular/src/app/create-account/create-account.component.ts deleted file mode 100644 index f22aa2c..0000000 --- a/web/angular/src/app/create-account/create-account.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Component, OnInit} from '@angular/core'; -import {Credentials} from "../models/credentials"; - -@Component({ - selector: 'app-create-account', - templateUrl: './create-account.component.html', - styleUrls: ['./create-account.component.css'] -}) -export class CreateAccountComponent implements OnInit { - - credentials: Credentials = {}; - - constructor() { - } - - ngOnInit() { - } - - canCreate(): boolean { - return this.credentials.username && this.credentials.username != "" && - this.credentials.password == this.credentials.repeatPassword - } - - onClick() { - alert("e") - } - -} diff --git a/web/angular/src/app/create-project/create-project.component.ts b/web/angular/src/app/create-project/create-project.component.ts index 379bcd8..457163e 100644 --- a/web/angular/src/app/create-project/create-project.component.ts +++ b/web/angular/src/app/create-project/create-project.component.ts @@ -12,7 +12,7 @@ import {Router} from "@angular/router"; }) export class CreateProjectComponent implements OnInit { - project = new Project(); + project = {}; constructor(private apiService: ApiService, private messengerService: MessengerService, diff --git a/web/angular/src/app/login/login.component.css b/web/angular/src/app/login/login.component.css index ef0ee71..c94ffd0 100644 --- a/web/angular/src/app/login/login.component.css +++ b/web/angular/src/app/login/login.component.css @@ -1,3 +1,8 @@ .mat-form-field { width: 100%; } + +.pad { + padding-top: 2em; +} + diff --git a/web/angular/src/app/login/login.component.html b/web/angular/src/app/login/login.component.html index 001e58e..b5b9fd4 100644 --- a/web/angular/src/app/login/login.component.html +++ b/web/angular/src/app/login/login.component.html @@ -1,8 +1,8 @@
- {{"login.title" | translate}} - -
+ + + {{"login.username" | translate}} @@ -12,11 +12,32 @@ {{ "login.password" | translate}} - -
- - - + + + + + + {{"login.username" | translate}} + {{credentials.username?.length || 0}}/16 + + + + + {{ "login.password" | translate}} + + + + + {{ "login.repeat_password" | translate}} + + + + + +
diff --git a/web/angular/src/app/login/login.component.ts b/web/angular/src/app/login/login.component.ts index af2b29d..6ae87b7 100644 --- a/web/angular/src/app/login/login.component.ts +++ b/web/angular/src/app/login/login.component.ts @@ -1,5 +1,9 @@ import {Component, OnInit} from '@angular/core'; import {Credentials} from "../models/credentials"; +import {ApiService} from "../api.service"; +import {MessengerService} from "../messenger.service"; +import {Router} from "@angular/router"; +import {AuthService} from "../auth.service"; @Component({ selector: 'app-login', @@ -10,13 +14,34 @@ export class LoginComponent implements OnInit { credentials: Credentials = {}; - constructor() { + constructor(private apiService: ApiService, + private messengerService: MessengerService, + private router: Router, + private authService: AuthService) { } ngOnInit() { } - onClick() { + login() { + this.authService.login(this.credentials) + } + register() { + this.apiService.register(this.credentials) + .subscribe( + () => { + this.router.navigateByUrl("/account") + }, + error => { + console.log(error); + this.messengerService.show(error.error.message); + } + ) + } + + canCreate(): boolean { + return this.credentials.username && this.credentials.username != "" && + this.credentials.password == this.credentials.repeatPassword } } diff --git a/web/angular/src/app/logs/logs.component.ts b/web/angular/src/app/logs/logs.component.ts index 1d9f2f8..80a6332 100644 --- a/web/angular/src/app/logs/logs.component.ts +++ b/web/angular/src/app/logs/logs.component.ts @@ -1,5 +1,6 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import {ApiService} from "../api.service"; +import {LogEntry} from "../models/logentry"; import _ from "lodash" import * as moment from "moment"; diff --git a/web/angular/src/app/logs/logentry.ts b/web/angular/src/app/models/logentry.ts similarity index 74% rename from web/angular/src/app/logs/logentry.ts rename to web/angular/src/app/models/logentry.ts index fc64aee..b1caa99 100644 --- a/web/angular/src/app/logs/logentry.ts +++ b/web/angular/src/app/models/logentry.ts @@ -1,4 +1,4 @@ -interface LogEntry { +export interface LogEntry { level: string, message: string, data: any, diff --git a/web/angular/src/app/models/manager.ts b/web/angular/src/app/models/manager.ts new file mode 100644 index 0000000..d194efe --- /dev/null +++ b/web/angular/src/app/models/manager.ts @@ -0,0 +1,3 @@ +interface Manager { + username: string +} diff --git a/web/angular/src/app/models/project.ts b/web/angular/src/app/models/project.ts index f74b5ef..d92c6c0 100644 --- a/web/angular/src/app/models/project.ts +++ b/web/angular/src/app/models/project.ts @@ -1,11 +1,10 @@ -export class Project { - - public id: number; - public priority: number; - public motd: string; - public name: string; - public clone_url: string; - public git_repo: string; - public version: string; - public public: boolean; +export interface Project { + id: number; + priority: number; + motd: string; + name: string; + clone_url: string; + git_repo: string; + version: string; + public: boolean; } diff --git a/web/angular/src/app/project-list/project-list.component.html b/web/angular/src/app/project-list/project-list.component.html index d0d8962..1d48849 100755 --- a/web/angular/src/app/project-list/project-list.component.html +++ b/web/angular/src/app/project-list/project-list.component.html @@ -19,6 +19,11 @@ build{{"project.update" | translate}} + + {{"projects.empty" | translate}} + + diff --git a/web/angular/src/assets/i18n/en.json b/web/angular/src/assets/i18n/en.json index 7cf670f..1ecf551 100644 --- a/web/angular/src/assets/i18n/en.json +++ b/web/angular/src/assets/i18n/en.json @@ -4,7 +4,8 @@ "langSelect": "Language", "logs": "Logs", "project_list": "Projects", - "new_project": "New Project" + "new_project": "New Project", + "login": "Login" }, "logs": { "filter": "Filter", @@ -21,7 +22,8 @@ }, "projects": { "projects": "Projects", - "dashboard": "Dashboard" + "dashboard": "Dashboard", + "empty": "No projects" }, "title": { "": "Index", @@ -30,7 +32,8 @@ "log": "Logs", "new_project": "New project", "login": "Login", - "new_account": "Create account" + "new_account": "Create account", + "account": "Account details" }, "project": { "name": "Project name", @@ -51,14 +54,15 @@ "metadata": "Project metadata" }, "login": { - "title": "Manager login", + "title": "Login", "login": "Login", "username": "Username", "password": "Password", - "repeat_password": "Repeat password" + "repeat_password": "Repeat password", + "create_account": "" }, "create_account": { - "title": "Create manager account", + "title": "Register", "create": "Create account" } } diff --git a/web/angular/src/assets/i18n/fr.json b/web/angular/src/assets/i18n/fr.json index a7b81d4..ceb75e9 100644 --- a/web/angular/src/assets/i18n/fr.json +++ b/web/angular/src/assets/i18n/fr.json @@ -4,7 +4,8 @@ "langSelect": "Langue", "logs": "Journal", "project_list": "Projets", - "new_project": "Nouveau projet" + "new_project": "Nouveau projet", + "login": "Ouvrir un session" }, "logs": { "filter": "Filtrer", @@ -21,7 +22,8 @@ }, "projects": { "projects": "Projets", - "dashboard": "Tableau de bord" + "dashboard": "Tableau de bord", + "empty": "Pas de projets" }, "title": { "": "Accueil", @@ -31,7 +33,8 @@ "new_project": "Nouveau projet", "update": "Modifier", "login": "Ouverture de session", - "new_account": "Création de compte" + "new_account": "Création de compte", + "account": "Compte" }, "project": { "name": "Nom du projet", @@ -52,14 +55,15 @@ "metadata": "Métadonnés du projet" }, "login": { - "title": "Identification - chef de projet", + "title": "Ouvrir un session", "login": "Ouvrir un session", "username": "Nom d'utilisateur", "password": "Mot de passe", - "repeat_password": "Répéter le mot de passe" + "repeat_password": "Répéter le mot de passe", + "create_account": "Créer un compte" }, "create_account": { - "title": "Création d'un compte de chef de projet", + "title": "Créer un compte", "create": "Créer un compte" } } diff --git a/web/angular/src/styles.css b/web/angular/src/styles.css index 186df79..363904a 100644 --- a/web/angular/src/styles.css +++ b/web/angular/src/styles.css @@ -70,3 +70,11 @@ body { max-width: 720px; } } + +.mat-tab-label { + width: 100%; +} + +.mat-tab-body { + padding-top: 1em; +}