fix:#3 refactored functions

This commit is contained in:
Elmar Kresse
2024-07-24 11:25:59 +02:00
parent c15dbfeebb
commit e4bde20397
3 changed files with 69 additions and 88 deletions

View File

@ -16,26 +16,7 @@
import { BSON } from "bson"; import { BSON } from "bson";
import { RoomOccupancyList } from "@/model/roomOccupancyList.ts"; import { RoomOccupancyList } from "@/model/roomOccupancyList.ts";
import { import { addMonths } from "date-fns";
Duration,
NormalizedInterval,
add,
addDays,
addMinutes,
addMonths,
clamp,
differenceInMinutes,
eachDayOfInterval,
endOfDay,
interval,
isAfter,
isBefore,
isEqual,
max,
min,
startOfDay,
subDays,
} from "date-fns";
import { formatYearMonthDay } from "@/helpers/dates"; import { formatYearMonthDay } from "@/helpers/dates";
const END_OF_SUMMER_SEMESTER = "0930"; const END_OF_SUMMER_SEMESTER = "0930";
@ -88,19 +69,19 @@ export async function fetchRoomOccupancy(
to_date?: string, to_date?: string,
): Promise<RoomOccupancyList> { ): Promise<RoomOccupancyList> {
if (from_date == undefined) { if (from_date == undefined) {
let new_from_date = getSemesterStart(new Date()); const new_from_date = getSemesterStart(new Date());
from_date = new_from_date.toISOString(); from_date = new_from_date.toISOString();
} }
if (to_date == undefined) { if (to_date == undefined) {
let new_to_date = getSemesterStart(addMonths(new Date(), 6)); const new_to_date = getSemesterStart(addMonths(new Date(), 6));
to_date = new_to_date.toISOString(); to_date = new_to_date.toISOString();
} }
var roomOccupancyList: RoomOccupancyList = new RoomOccupancyList( let roomOccupancyList: RoomOccupancyList = new RoomOccupancyList(
new Date(), new Date(),
0, 0,
0, 0,
[], [],
); );
await fetch("/api/schedule/rooms?from=" + from_date + "&to=" + to_date) await fetch("/api/schedule/rooms?from=" + from_date + "&to=" + to_date)

View File

@ -21,17 +21,16 @@ import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid"; import dayGridPlugin from "@fullcalendar/daygrid";
import interactionPlugin from "@fullcalendar/interaction"; import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid"; import timeGridPlugin from "@fullcalendar/timegrid";
import { computed, ComputedRef, inject, ref, Ref } from "vue"; import {computed, ComputedRef, inject, ref, Ref, watch} from "vue";
import { CalendarOptions, DatesSetArg, EventInput } from "@fullcalendar/core"; import {CalendarOptions, DatesSetArg, EventInput} from "@fullcalendar/core";
import { useI18n } from "vue-i18n"; import {useI18n} from "vue-i18n";
import allLocales from "@fullcalendar/core/locales-all"; import allLocales from "@fullcalendar/core/locales-all";
import router from "@/router"; import router from "@/router";
import { formatYearMonthDay } from "@/helpers/dates"; import {formatYearMonthDay} from "@/helpers/dates";
import { useQuery } from "@tanstack/vue-query"; import {useQuery} from "@tanstack/vue-query";
import { watch } from "vue"; import {fetchRoomOccupancy} from "@/api/fetchRoomOccupancy";
import { fetchRoomOccupancy } from "@/api/fetchRoomOccupancy"; import {isValid} from "date-fns";
import { isValid } from "date-fns"; import {RoomOccupancyList} from "@/model/roomOccupancyList";
import { RoomOccupancyList } from "@/model/roomOccupancyList";
const { t } = useI18n({ useScope: "global" }); const { t } = useI18n({ useScope: "global" });
@ -78,17 +77,16 @@ const selectedRoom = computed(() => props.room);
* @returns Anonymized occupancy events * @returns Anonymized occupancy events
*/ */
function transformData(data: RoomOccupancyList) { function transformData(data: RoomOccupancyList) {
const events = data return data
.decodeOccupancy( .decodeOccupancy(
selectedRoom.value, selectedRoom.value,
new Date(currentDateFrom.value), new Date(currentDateFrom.value),
new Date(currentDateTo.value), new Date(currentDateTo.value),
) )
.map((event, index) => ({ .map((event, index) => ({
id: index, id: index,
event: event, event: event,
})); }));
return events;
} }
const { data: occupancy } = useQuery({ const { data: occupancy } = useQuery({

View File

@ -14,7 +14,7 @@
//You should have received a copy of the GNU Affero General Public License //You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>. //along with this program. If not, see <https://www.gnu.org/licenses/>.
import { Binary } from "bson"; import {Binary, Document} from "bson";
import { AnonymizedOccupancy } from "./event"; import { AnonymizedOccupancy } from "./event";
import { import {
Duration, Duration,
@ -93,7 +93,7 @@ export class RoomOccupancyList {
const roomOccupancy = this.rooms.find((r) => r.name === room); const roomOccupancy = this.rooms.find((r) => r.name === room);
// Get start and end of decoded time range (within encoded list and requested range) // Get start and end of decoded time range (within encoded list and requested range)
let decodeInterval = interval( const decodeInterval = interval(
clamp(from, this.getOccupancyInterval()), clamp(from, this.getOccupancyInterval()),
clamp(to, this.getOccupancyInterval()), clamp(to, this.getOccupancyInterval()),
); );
@ -108,7 +108,7 @@ export class RoomOccupancyList {
const occupancyList = []; const occupancyList = [];
let { decodeSliceStart, decodeSlice } = this.sliceOccupancy( const { decodeSliceStart, decodeSlice } = this.sliceOccupancy(
decodeInterval, decodeInterval,
roomOccupancy.occupancy.buffer, roomOccupancy.occupancy.buffer,
); );
@ -145,10 +145,10 @@ export class RoomOccupancyList {
/** /**
* Slice the important parts of the occupancy list for a given time range. * Slice the important parts of the occupancy list for a given time range.
* @param from the start of the time range.
* @param to the end of the time range.
* @returns a new occupancy byte array with the starting time of the first byte * @returns a new occupancy byte array with the starting time of the first byte
* @throws an error, if the selected time range is outside of the occupancy list. * @throws an error, if the selected time range is outside of the occupancy list.
* @param decodeInterval
* @param occupancy
*/ */
private sliceOccupancy( private sliceOccupancy(
decodeInterval: NormalizedInterval, decodeInterval: NormalizedInterval,
@ -156,14 +156,14 @@ export class RoomOccupancyList {
): { decodeSliceStart: Date; decodeSlice: Uint8Array } { ): { decodeSliceStart: Date; decodeSlice: Uint8Array } {
// Calculate the slice of bytes, that are needed to decode the requested time range // Calculate the slice of bytes, that are needed to decode the requested time range
// Note: differenceInMinutes calculates (left - right) // Note: differenceInMinutes calculates (left - right)
let minutesFromStart = differenceInMinutes( const minutesFromStart = differenceInMinutes(
decodeInterval.start, decodeInterval.start,
this.start, this.start,
); );
let minutesToEnd = differenceInMinutes(decodeInterval.end, this.start); const minutesToEnd = differenceInMinutes(decodeInterval.end, this.start);
let firstByte = Math.floor(minutesFromStart / this.granularity / 8); const firstByte = Math.floor(minutesFromStart / this.granularity / 8);
let lastByte = Math.ceil(minutesToEnd / this.granularity / 8); const lastByte = Math.ceil(minutesToEnd / this.granularity / 8);
// check if firstByte and lastByte are within the bounds of the occupancy array and throw an error if not // check if firstByte and lastByte are within the bounds of the occupancy array and throw an error if not
if ( if (
@ -175,11 +175,11 @@ export class RoomOccupancyList {
throw new Error("Requested time range is outside of the occupancy list."); throw new Error("Requested time range is outside of the occupancy list.");
} }
let decodeSliceStart = addMinutes( const decodeSliceStart = addMinutes(
this.start, this.start,
firstByte * 8 * this.granularity, firstByte * 8 * this.granularity,
); );
let decodeSlice = occupancy.buffer.slice(firstByte, lastByte); const decodeSlice = occupancy.buffer.slice(firstByte, lastByte);
return { decodeSliceStart, decodeSlice: new Uint8Array(decodeSlice) }; return { decodeSliceStart, decodeSlice: new Uint8Array(decodeSlice) };
} }
@ -209,43 +209,44 @@ export class RoomOccupancyList {
granularity: number, granularity: number,
room: string, room: string,
): AnonymizedOccupancy[] { ): AnonymizedOccupancy[] {
let occupancyList = []; const occupancyList = [];
let firstOccupancyBit: number | null = null; let firstOccupancyBit: number | null = null;
// Iterate over all bytes that are in the array // Iterate over all bytes that are in the array
for (let byte_i = 0; byte_i < occupancy.length; byte_i++) { for (let byte_i = 0; byte_i < occupancy.length; byte_i++) {
let byte = occupancy[byte_i]; const byte = occupancy[byte_i];
// Iterate over all bits in the current byte // Iterate over all bits in the current byte
for (let bit_i = 0; bit_i < 8; bit_i++) { for (let bit_i = 0; bit_i < 8; bit_i++) {
let isOccupied = (byte & (1 << (7 - bit_i))) !== 0; const isOccupied = (byte & (1 << (7 - bit_i))) !== 0;
const calculateOccupancyBitIndex = (byte_i: number, bit_i: number) => byte_i * 8 + bit_i;
if (firstOccupancyBit === null && isOccupied) { if(firstOccupancyBit === null){
firstOccupancyBit = byte_i * 8 + bit_i; if (isOccupied) {
} else if (firstOccupancyBit !== null && !isOccupied) { firstOccupancyBit = calculateOccupancyBitIndex(byte_i, bit_i);
let startTime = addMinutes(start, firstOccupancyBit * granularity); }
let endTime = addMinutes(start, (byte_i * 8 + bit_i) * granularity); } else {
if (!isOccupied) {
// add event between start and end of a block of boolean true values const startTime = addMinutes(start, firstOccupancyBit * granularity);
occupancyList.push( const endTime = addMinutes(start, calculateOccupancyBitIndex(byte_i, bit_i) * granularity);
new AnonymizedOccupancy( // add event between start and end of a block of boolean true values
startTime.toISOString(), occupancyList.push(
endTime.toISOString(), new AnonymizedOccupancy(
room, startTime.toISOString(),
false, endTime.toISOString(),
false, room,
), false,
); false,
),
firstOccupancyBit = null; );
firstOccupancyBit = null;
}
}
} }
} }
}
// add last event if it is still ongoing // add last event if it is still ongoing
if (firstOccupancyBit !== null) { if (firstOccupancyBit !== null) {
let startTime = addMinutes(start, firstOccupancyBit * granularity); const startTime = addMinutes(start, firstOccupancyBit * granularity);
let endTime = addMinutes(start, occupancy.length * 8 * granularity); const endTime = addMinutes(start, occupancy.length * 8 * granularity);
occupancyList.push( occupancyList.push(
new AnonymizedOccupancy( new AnonymizedOccupancy(
@ -265,6 +266,7 @@ export class RoomOccupancyList {
* Generate a list of AnonymizedOccupancy objects for a given time range. * Generate a list of AnonymizedOccupancy objects for a given time range.
* The generated events are always lying within the time range [START_OF_DAY, END_OF_DAY]. * The generated events are always lying within the time range [START_OF_DAY, END_OF_DAY].
* *
* @param rooms
* @param from The start time within the specified start day. * @param from The start time within the specified start day.
* @param to The end time within the specified end day. * @param to The end time within the specified end day.
* @returns a list of AnonymizedEventDTO objects, from start to end. * @returns a list of AnonymizedEventDTO objects, from start to end.
@ -282,11 +284,11 @@ export class RoomOccupancyList {
} }
return eachDayOfInterval({ start: from, end: to }).map((day) => { return eachDayOfInterval({ start: from, end: to }).map((day) => {
let startTime = max([ const startTime = max([
from, from,
RoomOccupancyList.setTimeOfDay(day, START_OF_WORKDAY), RoomOccupancyList.setTimeOfDay(day, START_OF_WORKDAY),
]); ]);
let endTime = min([ const endTime = min([
to, to,
RoomOccupancyList.setTimeOfDay(day, END_OF_WORKDAY), RoomOccupancyList.setTimeOfDay(day, END_OF_WORKDAY),
]); ]);
@ -307,13 +309,13 @@ export class RoomOccupancyList {
* @param json the JS object to read from. * @param json the JS object to read from.
* @returns a RoomOccupancyList object. * @returns a RoomOccupancyList object.
*/ */
public static fromJSON(json: any): RoomOccupancyList { public static fromJSON(json: Document): RoomOccupancyList {
return new RoomOccupancyList( return new RoomOccupancyList(
json.start, json.start,
json.granularity, json.granularity,
json.blocks, json.blocks,
json.rooms.map( json.rooms.map(
(room: any) => new RoomOccupancy(room.name, room.occupancy), (room: { name: string, occupancy: Binary }) => new RoomOccupancy(room.name, room.occupancy),
), ),
); );
} }