Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions src/aws/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ import {
Post,
Headers,
Body,
Query,
UseGuards,
} from "@nestjs/common";
import { AuthService } from "./auth.service";
import { WriteEntryToTable, UserTimesheets } from "../dynamodb";
import { getTimesheetsForUsersInGivenTimeFrame, doUUIDSExistInCompanies, GetCompaniesForUser, areUUIDsValid } from "../dynamodb";
import TokenClient from './cognito/cognito.keyparser'
import { TimeSheetSchema } from 'src/db/schemas/Timesheet';
import * as frontendTimesheetSchemas from 'src/db/schemas/Timesheet'
import { Roles } from "src/utils/decorators/roles.decorators"; // idk if this is correct
import { RolesGuard } from 'src/utils/guards/roles.guard';
import { UploadTimesheet } from 'src/db/timesheets/UploadTimesheet';
import { TimesheetUpdateRequest } from 'src/db/schemas/UpdateTimesheet';
import { Formatter } from 'src/db/timesheets/Formatter';


@Controller("auth")
@UseGuards(RolesGuard)
export class AuthController {
Expand Down Expand Up @@ -51,4 +52,64 @@ export class AuthController {
}
return [];
}

@Get("getTimesheet")
//@Roles('breaktime-management-role')
//@Roles("breaktime-admin", "breaktime-supervisor")
public async get_timesheets(
@Headers() headers: any,
@Query("userIds") userIDs?: string[]
): Promise<uuidToTimesheetMapping[]> {
// if supervisors dont have access to a uuid throw an error
// if supervisor or admin request non existent uuid throw an error

// if supervisor ensure all uuids are in company
// if admin just make sure theyre all valid

// if associate only return their timesheet

const userID = await TokenClient.grabUserID(headers);
let areAllUUIDsValid;

if (!userIDs) {
if (1 == 1) { // associate
userIDs = [userID]
} else if (2 === 2) { // supervisor
userIDs = [] // get all users in their companies
} else if (3 === 3) { // admin
userIDs = [] // get all users they own
} else {
// no role no access
// throw error
}
}

if (1 === 1) { // associate
areAllUUIDsValid = (userIDs.length === 1 && userID === userIDs[0])

} else if (2 === 2) { // supervisor
const supervisorCompanies = (await GetCompaniesForUser(userID)).SupervisorCompanyIDs
areAllUUIDsValid = await doUUIDSExistInCompanies(userIDs, supervisorCompanies)

} else if (3 === 3) { //admin
areAllUUIDsValid = await areUUIDsValid(userIDs);

} else {
// no role no access
// throw error
}

if (areAllUUIDsValid) {
return await getTimesheetsForUsersInGivenTimeFrame(userIDs);
} else{
// throw error
}

//await getTimesheetsForUsersInGivenTimeFrame(['77566d69-3b61-452a-afe8-73dcda96f876']);
}
}

export type uuidToTimesheetMapping = {
uuid: string,
timesheet: TimeSheetSchema
};
124 changes: 124 additions & 0 deletions src/dynamodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
} from "@aws-sdk/client-dynamodb";
import { unmarshall, marshall } from "@aws-sdk/util-dynamodb";
import * as dotenv from "dotenv";
import moment = require("moment");

import { timesheetToUpload } from "./utils";
import {TimeSheetSchema} from './db/schemas/Timesheet'
import { CompanySchema, UserCompaniesSchema } from './db/schemas/CompanyUsers';

Expand Down Expand Up @@ -160,3 +162,125 @@ export async function WriteEntryToTable(table:TimeSheetSchema): Promise<Boolean>
});
return true;
}
// EndDate should be start date plus one week
export async function getTimesheetsForUsersInGivenTimeFrame(uuids: string[], StartDate:number = moment().startOf('week').subtract(1, 'week').unix() , EndDate:number = moment().endOf('week').unix()): Promise<any> {

if (StartDate > EndDate) {
throw new Error("Invalid EndDate")
}

let result = []

for (let uuid of uuids) {
const command = new QueryCommand({
TableName: "BreaktimeTimesheets",
KeyConditionExpression: "UserID = :s",
ExpressionAttributeValues: {
":s": { S: `${uuid}` },
},
ExpressionAttributeNames: {
"#S": "Status"
},
ProjectionExpression: "UserID, TimesheetID, CompanyID, ScheduleData, StartDate, #S, WeekNotes"
});

// get the items from DynamoDB with our query
const dynamoRawResult = await client.send(command);

if (dynamoRawResult == null || dynamoRawResult.Items == null) {
throw new Error("Invalid response from DynamoDB, got undefined/null");
}

// Convert Dynamo items to JS objects
const unmarshalledItems = dynamoRawResult.Items.map((i) => unmarshall(i));

// Parse the items into our expected Company schema.
const timesheetData = unmarshalledItems.map((i) => TimeSheetSchema.parse(i));

const uuidSet = new Set(uuids)


// TODO: have to check here the timesheets for all weeks exist then and create empty if not
let modifiedTimesheetData = timesheetData.filter((sheet) => {return uuidSet.has(sheet.UserID) && sheet.StartDate >= StartDate && sheet.StartDate < EndDate})

let existingWeeks = new Set()

for (const sheet of modifiedTimesheetData) {
// maybe move to utils and can in theory have locale based issues so configure moment project wide
const beginningOfWeekDate = moment.unix(sheet.StartDate).set('second', 0).set('minute', 0).set('hour', 0).set('millisecond', 0).startOf('week').unix()
existingWeeks.add(beginningOfWeekDate) // make it sunday 00:00:00
}

console.log(existingWeeks, StartDate)
for (const m = moment.unix(StartDate); m.isBefore(moment.unix(EndDate)); m.add(1, 'week')) {
if (!(m.unix() in existingWeeks)) {
const newSheet = timesheetToUpload(uuid, "Company 55"); // TODO: should loop through companies user was active in and do it like that
WriteEntryToTable(newSheet);
// add to modifiedTimesheetData
modifiedTimesheetData.push(newSheet);
}

}

// go through modified timesheets
// make a set of what weeks it has
// go through start to end and check that it has all weeks

// modifiedTimesheetData not sorted by date but can be sorted

const uuidToTimesheet = {"uuid": uuid, timesheet: modifiedTimesheetData}

result.push(uuidToTimesheet);
};

return result
}

export async function doUUIDSExistInCompanies(uuids: string[], companies: string[]): Promise<Boolean> {

const dynamoKeys = companies.map((company) => {return {CompanyID: { S: company}}})

const command = new BatchGetItemCommand({
RequestItems: {
BreaktimeCompanyToUsers : {
Keys : dynamoKeys,
ProjectionExpression : "AssociateIDs"
}
}
});

const dynamoRawResult = await client.send(command);

if (dynamoRawResult == null || dynamoRawResult.Responses == null) {
throw new Error("Invalid response from DynamoDB, got undefined/null");
}

const results = dynamoRawResult.Responses.BreaktimeCompanyToUsers.map((i) => unmarshall(i))[0].AssociateIDs;

// so check results are same as uuids
return results.sort().toString() === uuids.sort().toString();
}

export async function areUUIDsValid(uuids: string[]): Promise<Boolean> {

const dynamoKeys = uuids.map((uuid) => {return {UserID: { S: uuid}}})

const command = new BatchGetItemCommand({
RequestItems: {
BreaktimeUserToCompanies : {
Keys : dynamoKeys,
ProjectionExpression : "UserID"
}
}
});

const dynamoRawResult = await client.send(command);

if (dynamoRawResult == null || dynamoRawResult.Responses == null) {
throw new Error("Invalid response from DynamoDB, got undefined/null");
}

const results = dynamoRawResult.Responses.BreaktimeUserToCompanies;

return results.length === uuids.length;
}
21 changes: 21 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TimeSheetSchema, TimesheetStatus } from "../src/db/schemas/Timesheet"
const moment = require('moment-timezone');

export const timesheetToUpload = (UUID: string, CompanyID: string) =>
{
return TimeSheetSchema.parse({
TimesheetID: Math.round(Math.random() * 1000000000),
UserID: UUID,
StartDate: moment().startOf('week').day(0).unix(),
Status: TimesheetStatus.parse({
HoursSubmitted: undefined,
HoursReviewed: undefined,
ScheduleSubmitted: undefined,
Finalized: undefined
}),
CompanyID: CompanyID,
HoursData: [],
ScheduleData: [],
WeekNotes: []
})
}