Compare commits
No commits in common. "5696310a687e7d59a5469fe870074034164b42fe" and "1a412dc8a06b335c1d7d50b5311d465f0bffa3be" have entirely different histories.
5696310a68
...
1a412dc8a0
10 changed files with 40 additions and 229 deletions
|
@ -2,7 +2,6 @@ package database
|
|||
|
||||
import (
|
||||
"embed"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"ttime/internal/types"
|
||||
|
||||
|
@ -31,7 +30,6 @@ type Database interface {
|
|||
GetProject(projectId int) (types.Project, error)
|
||||
GetUserRole(username string, projectname string) (string, error)
|
||||
GetWeeklyReport(username string, projectName string, week int) (types.WeeklyReport, error)
|
||||
SignWeeklyReport(reportId int, projectManagerId int) error
|
||||
}
|
||||
|
||||
// This struct is a wrapper type that holds the database connection
|
||||
|
@ -272,8 +270,7 @@ func (d *Db) GetWeeklyReport(username string, projectName string, week int) (typ
|
|||
admin_time,
|
||||
own_work_time,
|
||||
study_time,
|
||||
testing_time,
|
||||
signed_by
|
||||
testing_time
|
||||
FROM
|
||||
weekly_reports
|
||||
WHERE
|
||||
|
@ -285,34 +282,6 @@ func (d *Db) GetWeeklyReport(username string, projectName string, week int) (typ
|
|||
return report, err
|
||||
}
|
||||
|
||||
// SignWeeklyReport signs a weekly report by updating the signed_by field
|
||||
// with the provided project manager's ID, but only if the project manager
|
||||
// is in the same project as the report
|
||||
func (d *Db) SignWeeklyReport(reportId int, projectManagerId int) error {
|
||||
// Retrieve the project ID associated with the report
|
||||
var reportProjectID int
|
||||
err := d.Get(&reportProjectID, "SELECT project_id FROM weekly_reports WHERE report_id = ?", reportId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Retrieve the project ID associated with the project manager
|
||||
var managerProjectID int
|
||||
err = d.Get(&managerProjectID, "SELECT project_id FROM user_roles WHERE user_id = ? AND p_role = 'project_manager'", projectManagerId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the project manager is in the same project as the report
|
||||
if reportProjectID != managerProjectID {
|
||||
return errors.New("project manager doesn't have permission to sign the report")
|
||||
}
|
||||
|
||||
// Update the signed_by field of the specified report
|
||||
_, err = d.Exec("UPDATE weekly_reports SET signed_by = ? WHERE report_id = ?", projectManagerId, reportId)
|
||||
return err
|
||||
}
|
||||
|
||||
// Reads a directory of migration files and applies them to the database.
|
||||
// This will eventually be used on an embedded directory
|
||||
func (d *Db) Migrate() error {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -411,128 +410,3 @@ func TestGetWeeklyReport(t *testing.T) {
|
|||
}
|
||||
// Check other fields similarly
|
||||
}
|
||||
|
||||
func TestSignWeeklyReport(t *testing.T) {
|
||||
db, err := setupState()
|
||||
if err != nil {
|
||||
t.Error("setupState failed:", err)
|
||||
}
|
||||
|
||||
// Add project manager
|
||||
err = db.AddUser("projectManager", "password")
|
||||
if err != nil {
|
||||
t.Error("AddUser failed:", err)
|
||||
}
|
||||
|
||||
// Add a regular user
|
||||
err = db.AddUser("testuser", "password")
|
||||
if err != nil {
|
||||
t.Error("AddUser failed:", err)
|
||||
}
|
||||
|
||||
// Add project
|
||||
err = db.AddProject("testproject", "description", "projectManager")
|
||||
if err != nil {
|
||||
t.Error("AddProject failed:", err)
|
||||
}
|
||||
|
||||
// Add both regular users as members to the project
|
||||
err = db.AddUserToProject("testuser", "testproject", "member")
|
||||
if err != nil {
|
||||
t.Error("AddUserToProject failed:", err)
|
||||
}
|
||||
|
||||
err = db.AddUserToProject("projectManager", "testproject", "project_manager")
|
||||
if err != nil {
|
||||
t.Error("AddUserToProject failed:", err)
|
||||
}
|
||||
|
||||
// Add a weekly report for one of the regular users
|
||||
err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1)
|
||||
if err != nil {
|
||||
t.Error("AddWeeklyReport failed:", err)
|
||||
}
|
||||
|
||||
// Retrieve the added report
|
||||
report, err := db.GetWeeklyReport("testuser", "testproject", 1)
|
||||
if err != nil {
|
||||
t.Error("GetWeeklyReport failed:", err)
|
||||
}
|
||||
|
||||
// Print project manager's ID
|
||||
projectManagerID, err := db.GetUserId("projectManager")
|
||||
if err != nil {
|
||||
t.Error("GetUserId failed:", err)
|
||||
}
|
||||
fmt.Println("Project Manager's ID:", projectManagerID)
|
||||
|
||||
// Sign the report with the project manager
|
||||
err = db.SignWeeklyReport(report.ReportId, projectManagerID)
|
||||
if err != nil {
|
||||
t.Error("SignWeeklyReport failed:", err)
|
||||
}
|
||||
|
||||
// Retrieve the report again to check if it's signed
|
||||
signedReport, err := db.GetWeeklyReport("testuser", "testproject", 1)
|
||||
if err != nil {
|
||||
t.Error("GetWeeklyReport failed:", err)
|
||||
}
|
||||
|
||||
// Ensure the report is signed by the project manager
|
||||
if *signedReport.SignedBy != projectManagerID {
|
||||
t.Errorf("Expected SignedBy to be %d, got %d", projectManagerID, *signedReport.SignedBy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignWeeklyReportByAnotherProjectManager(t *testing.T) {
|
||||
db, err := setupState()
|
||||
if err != nil {
|
||||
t.Error("setupState failed:", err)
|
||||
}
|
||||
|
||||
// Add project manager
|
||||
err = db.AddUser("projectManager", "password")
|
||||
if err != nil {
|
||||
t.Error("AddUser failed:", err)
|
||||
}
|
||||
|
||||
// Add a regular user
|
||||
err = db.AddUser("testuser", "password")
|
||||
if err != nil {
|
||||
t.Error("AddUser failed:", err)
|
||||
}
|
||||
|
||||
// Add project
|
||||
err = db.AddProject("testproject", "description", "projectManager")
|
||||
if err != nil {
|
||||
t.Error("AddProject failed:", err)
|
||||
}
|
||||
|
||||
// Add the regular user as a member to the project
|
||||
err = db.AddUserToProject("testuser", "testproject", "member")
|
||||
if err != nil {
|
||||
t.Error("AddUserToProject failed:", err)
|
||||
}
|
||||
|
||||
// Add a weekly report for the regular user
|
||||
err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1)
|
||||
if err != nil {
|
||||
t.Error("AddWeeklyReport failed:", err)
|
||||
}
|
||||
|
||||
// Retrieve the added report
|
||||
report, err := db.GetWeeklyReport("testuser", "testproject", 1)
|
||||
if err != nil {
|
||||
t.Error("GetWeeklyReport failed:", err)
|
||||
}
|
||||
|
||||
anotherManagerID, err := db.GetUserId("projectManager")
|
||||
if err != nil {
|
||||
t.Error("GetUserId failed:", err)
|
||||
}
|
||||
|
||||
err = db.SignWeeklyReport(report.ReportId, anotherManagerID)
|
||||
if err == nil {
|
||||
t.Error("Expected SignWeeklyReport to fail with a project manager who is not in the project, but it didn't")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CREATE TABLE IF NOT EXISTS weekly_reports (
|
||||
CREATE TABLE weekly_reports (
|
||||
report_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
project_id INTEGER NOT NULL,
|
||||
|
|
|
@ -22,16 +22,13 @@ import (
|
|||
func (gs *GState) Register(c *fiber.Ctx) error {
|
||||
u := new(types.NewUser)
|
||||
if err := c.BodyParser(u); err != nil {
|
||||
println("Error parsing body")
|
||||
return c.Status(400).SendString(err.Error())
|
||||
}
|
||||
|
||||
println("Adding user:", u.Username)
|
||||
if err := gs.Db.AddUser(u.Username, u.Password); err != nil {
|
||||
return c.Status(500).SendString(err.Error())
|
||||
}
|
||||
|
||||
println("User added:", u.Username)
|
||||
return c.Status(200).SendString("User added")
|
||||
}
|
||||
|
||||
|
@ -60,11 +57,9 @@ func (gs *GState) Login(c *fiber.Ctx) error {
|
|||
// The body type is identical to a NewUser
|
||||
u := new(types.NewUser)
|
||||
if err := c.BodyParser(u); err != nil {
|
||||
println("Error parsing body")
|
||||
return c.Status(400).SendString(err.Error())
|
||||
}
|
||||
|
||||
println("Username:", u.Username)
|
||||
if !gs.Db.CheckUser(u.Username, u.Password) {
|
||||
println("User not found")
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
|
@ -79,16 +74,13 @@ func (gs *GState) Login(c *fiber.Ctx) error {
|
|||
|
||||
// Create token
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
println("Token created for user:", u.Username)
|
||||
|
||||
// Generate encoded token and send it as response.
|
||||
t, err := token.SignedString([]byte("secret"))
|
||||
if err != nil {
|
||||
println("Error signing token")
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
println("Successfully signed token for user:", u.Username)
|
||||
return c.JSON(fiber.Map{"token": t})
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,4 @@ type WeeklyReport struct {
|
|||
StudyTime int `json:"studyTime" db:"study_time"`
|
||||
// Total time spent on testing
|
||||
TestingTime int `json:"testingTime" db:"testing_time"`
|
||||
// The project manager who signed it
|
||||
SignedBy *int `json:"signedBy" db:"signed_by"`
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ describe("API", () => {
|
|||
username: "lol", // Add the username property
|
||||
password: "lol",
|
||||
};
|
||||
|
||||
const response = await api.registerUser(user);
|
||||
console.log(response.message);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toHaveProperty("userId");
|
||||
});
|
||||
|
@ -23,7 +24,7 @@ describe("API", () => {
|
|||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
|
||||
|
||||
const response = await api.createProject(project, token);
|
||||
console.log(response.message);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toHaveProperty("projectId");
|
||||
});
|
||||
|
@ -33,7 +34,7 @@ describe("API", () => {
|
|||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
|
||||
|
||||
const response = await api.renewToken(refreshToken);
|
||||
console.log(response.message);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toHaveProperty("accessToken");
|
||||
expect(response.data).toHaveProperty("refreshToken");
|
||||
|
@ -44,7 +45,7 @@ describe("API", () => {
|
|||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
|
||||
const username = "rrgumdzpmc";
|
||||
const response = await api.getUserProjects(username, token);
|
||||
console.log(response.message);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toHaveProperty("projects");
|
||||
});
|
||||
|
@ -64,7 +65,7 @@ describe("API", () => {
|
|||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
|
||||
|
||||
const response = await api.submitWeeklyReport(report, token);
|
||||
console.log(response.message);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toHaveProperty(
|
||||
"message",
|
||||
|
@ -79,7 +80,7 @@ describe("API", () => {
|
|||
};
|
||||
|
||||
const response = await api.login(user);
|
||||
console.log(response.message);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toHaveProperty("accessToken");
|
||||
expect(response.data).toHaveProperty("refreshToken");
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from "../Types/goTypes";
|
||||
|
||||
// This type of pattern should be hard to misuse
|
||||
export interface APIResponse<T> {
|
||||
interface APIResponse<T> {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
data?: T;
|
||||
|
|
|
@ -1,54 +1,34 @@
|
|||
import { NewUser } from "../Types/goTypes";
|
||||
import { api, APIResponse } from "../API/API";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
/*
|
||||
* Checks if user is in database with api.login and then sets proper authority level
|
||||
* TODO: change so that it checks for user type (admin, user, pm) somehow instead
|
||||
**/
|
||||
function LoginCheck(props: {
|
||||
username: string;
|
||||
password: string;
|
||||
setAuthority: Dispatch<SetStateAction<number>>;
|
||||
}): number {
|
||||
const user: NewUser = {
|
||||
username: props.username,
|
||||
password: props.password,
|
||||
function LoginCheck(props: { username: string; password: string }): number {
|
||||
//Example users for testing without backend, remove when using backend
|
||||
const admin: NewUser = {
|
||||
username: "admin",
|
||||
password: "123",
|
||||
};
|
||||
const pmanager: NewUser = {
|
||||
username: "pmanager",
|
||||
password: "123",
|
||||
};
|
||||
const user: NewUser = {
|
||||
username: "user",
|
||||
password: "123",
|
||||
};
|
||||
api
|
||||
.login(user)
|
||||
.then((response: APIResponse<string>) => {
|
||||
if (response.success) {
|
||||
if (response.data !== undefined) {
|
||||
const token = response.data;
|
||||
//TODO: change so that it checks for user type (admin, user, pm) instead
|
||||
if (token !== "" && props.username === "admin") {
|
||||
props.setAuthority((prevAuth) => {
|
||||
prevAuth = 1;
|
||||
return prevAuth;
|
||||
});
|
||||
} else if (token !== "" && props.username === "pm") {
|
||||
props.setAuthority((prevAuth) => {
|
||||
prevAuth = 2;
|
||||
return prevAuth;
|
||||
});
|
||||
} else if (token !== "" && props.username === "user") {
|
||||
props.setAuthority((prevAuth) => {
|
||||
prevAuth = 3;
|
||||
return prevAuth;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.error("Token was undefined");
|
||||
}
|
||||
} else {
|
||||
console.error("Token could not be fetched");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("An error occurred during login:", error);
|
||||
});
|
||||
|
||||
//TODO: Compare with db instead when finished
|
||||
if (props.username === admin.username && props.password === admin.password) {
|
||||
return 1;
|
||||
} else if (
|
||||
props.username === pmanager.username &&
|
||||
props.password === pmanager.password
|
||||
) {
|
||||
return 2;
|
||||
} else if (
|
||||
props.username === user.username &&
|
||||
props.password === user.password
|
||||
) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,9 @@ function LoginPage(props: {
|
|||
and if so, redirect to correct page */
|
||||
function handleSubmit(event: FormEvent<HTMLFormElement>): void {
|
||||
event.preventDefault();
|
||||
LoginCheck({
|
||||
username: username,
|
||||
password: password,
|
||||
setAuthority: props.setAuthority,
|
||||
props.setAuthority((prevAuth) => {
|
||||
prevAuth = LoginCheck({ username: username, password: password });
|
||||
return prevAuth;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ function PMProjectMembers(): JSX.Element {
|
|||
onClick={(): void => {
|
||||
return;
|
||||
}}
|
||||
type={"button"}
|
||||
/>
|
||||
</Link>
|
||||
<Link to="/PM-time-role">
|
||||
|
@ -23,7 +22,6 @@ function PMProjectMembers(): JSX.Element {
|
|||
onClick={(): void => {
|
||||
return;
|
||||
}}
|
||||
type={"button"}
|
||||
/>
|
||||
</Link>
|
||||
<BackButton />
|
||||
|
|
Loading…
Reference in a new issue