Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into glydric
Browse files Browse the repository at this point in the history
  • Loading branch information
Glydric committed Jan 25, 2024
2 parents 4b51b0b + 6b1d922 commit 6f98680
Show file tree
Hide file tree
Showing 52 changed files with 770 additions and 154 deletions.
5 changes: 5 additions & 0 deletions Backend/src/app/frontend/frontend.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ const filterParams = {
export class FrontendController {
constructor(private readonly databaseService: DatabaseService) {}

@Get(`cameras`)
getCameras() {
return this.databaseService.getCameras();
}

@ApiParam(filterParams)
@Get(`:filter(${filters.join('|')})/aggregate`)
getAggregateValues(
Expand Down
6 changes: 3 additions & 3 deletions Backend/src/app/login.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ export class LoginController {
examples: {
a: {
summary: 'Existing user',
value: {
value: {
name: process.env.CSD_USER,
password: process.env.CSD_PASSWORD,
},
},
b: {
summary: 'Non existing user',
b: {
summary: 'Non existing user',
value: { name: 'non', password: 'Basic' },
},
},
Expand Down
1 change: 1 addition & 0 deletions Backend/src/camera.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const cameraIds = [0, 1, 2, 3, 4, 5, 6, 7];
5 changes: 0 additions & 5 deletions Backend/src/cameraStream/cameraData.ts

This file was deleted.

18 changes: 17 additions & 1 deletion Backend/src/database/database.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import DataType from '../DataType';
import { FiltersAvailable } from '../validators/filters/filters.pipe';
import * as process from 'process';
import * as bcrypt from 'bcrypt';
import { cameraIds } from '../camera.config';

const url = `${process.env.MONGO_PROTOCOL ?? 'mongodb'}://${
process.env.MONGO_INITDB_ROOT_USERNAME
Expand Down Expand Up @@ -76,12 +77,23 @@ export class DatabaseService {
}
}

// If no camera exists it automatically creates one with the default config in camera.config.ts file
async initCameras() {
const size = await this.DB.collection('camera_names').countDocuments();
if (size == 0) {
await this.DB.collection(`camera_names`).insertMany(
cameraIds.map((id) => ({ id: id, name: 'No name' })),
);
}
}

constructor() {
const client = new MongoClient(url);

this.DB = client.db('csd');
this.initDBUser();
this.initDBNvr();
this.initCameras();
}

async addData(data: DataType<number>) {
Expand Down Expand Up @@ -119,6 +131,10 @@ export class DatabaseService {
else return res.toArray();
}

getCameras(): Promise<Document[]> {
return this.DB.collection('camera_names').find().toArray();
}

aggregateCamera(filter: FiltersAvailable): Promise<Document[]> {
return this.DB.collection('cameras')
.aggregate([
Expand Down Expand Up @@ -243,7 +259,7 @@ export class DatabaseService {
});

return {
ip: array[0].ip,
ip: process.env.NVR_IP_ADDRESS,
channels: array[0].channels,
};
}
Expand Down
23 changes: 23 additions & 0 deletions Frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Use the official Node.js image as the base image
FROM node:14-alpine

# Set the working directory inside the container
WORKDIR /app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the entire app to the working directory
COPY . .

# Build the Next.js app
RUN npm run build

# Expose the port that your Next.js app will run on
EXPOSE 3000

# Start the Next.js app
CMD ["npm", "start"]
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ type RequestHeaderOptions = {
Authorization?: string;
};

const accessToken = sessionStorage.getItem("access_token");
const headers: RequestHeaderOptions = {};

if (accessToken) {
headers.Authorization = `Bearer ${sessionStorage.getItem("access_token")}`;
}
export const axiosClient = axios.create({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
headers: { ...headers },
Expand Down
27 changes: 27 additions & 0 deletions Frontend/src/api/cameras.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Activity, AnyObject, Camera } from "@/types";
import { axiosClient } from "./axios-client";
import { endpoints } from "./endpoints";

type CamerasResponseDTO = Camera[];
type CameraSettingUpdateResponseDTO = any;

export const getCameras = () => {
return () =>
axiosClient
.get<CamerasResponseDTO>(`${endpoints.getCameras}`, {})
.then((result) => result.data);
};

export const updateCamera = async (configuration: AnyObject) => {
for (const key in configuration) {
try {
await axiosClient
.post<CamerasResponseDTO>(`${key}/${configuration[key]}`, {});
} catch (error: any) {
console.log(error);
}

}
return "Success"

};
9 changes: 8 additions & 1 deletion Frontend/src/api/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export const endpoints = {
/* authentication endpoints */
// authentication endpoints
login: "login",

// ِRecent activites endpoints
recentActivities: "intrusionDetection",
getIntrusionCount: "intrusionDetection/aggregate",

// Camera endpoints
getCameras: "cameras",
};
6 changes: 4 additions & 2 deletions Frontend/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { ReactQueryProvider } from "./react-query-provider";
export { ReactQueryProvider, queryClient } from "./react-query-provider";
export { axiosClient } from "./axios-client";

/* authentication methods */

export { login } from "./authentication/login";
export { getRecentActivities, getRecentActivitiesCount,getActivityImage } from "./recent-activities";
export { getCameras, updateCamera } from "./cameras";
2 changes: 1 addition & 1 deletion Frontend/src/api/react-query-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { QueryClient, QueryClientProvider } from "react-query";

const queryClient = new QueryClient();
export const queryClient = new QueryClient();

export const ReactQueryProvider = ({
children,
Expand Down
54 changes: 54 additions & 0 deletions Frontend/src/api/recent-activities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Activity } from "@/types";
import { axiosClient } from "./axios-client";
import { endpoints } from "./endpoints";

type RecentActivitiesResponseDTO = {
data: Activity[];
};

type RecentActivitiesCountResponseDTO = {
_id: string;
count: number;
}[];

type RecentActivityImageResponseDTO = {
data: any;
};

export const getRecentActivities = (top: number, skip: number) => {
return () =>
axiosClient
.get<RecentActivitiesResponseDTO>(
`${endpoints.recentActivities}/${top}/${skip}`,
{}
)
.then((result) => result.data);
};

export const getRecentActivitiesCount = () => {
return () =>
axiosClient
.get<RecentActivitiesCountResponseDTO>(
`${endpoints.getIntrusionCount}`,
{}
)
.then((result) => {
let totalCount = 0;

result.data.forEach((item) => {
totalCount += item.count;
});

return totalCount;
});
};

export const getActivityImage = (id: string, timestamp: string) => {
return () =>
axiosClient
.get<RecentActivityImageResponseDTO>(
`${id}/${timestamp}`,
{}
)
.then((result) => result.data);
};
10 changes: 2 additions & 8 deletions Frontend/src/app/recent-activities/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
"use client";
import { Table } from "@/components";
import { recentActivitiesData, recentActivitiesColumns } from "@/data";
import { RecentActivitiesContainer } from "@/containers";

export default function RecentActivities() {
return (
<div>
<Table
columns={recentActivitiesColumns}
data={recentActivitiesData}
pagination={{ total: recentActivitiesData.length }}
rowKey={"id"}
/>
<RecentActivitiesContainer />
</div>
);
}
10 changes: 10 additions & 0 deletions Frontend/src/app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client";
import { SettingsContainer } from "@/containers";

export default function Settings() {
return (
<div>
<SettingsContainer />
</div>
);
}
75 changes: 75 additions & 0 deletions Frontend/src/components/button/view-screenshot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Button } from "./button";
import { CameraOutlined } from "@ant-design/icons";
import { useModalSlice, useNotificationSlice } from "@/hooks";
import { useQuery } from "react-query";
import { getActivityImage } from "@/api";
import { Spin } from "antd";
import { useEffect } from "react";

type PropsType = {
cameraId: string;
timestamp: string;
};

/** This component renders screenshot button */
export const ViewScreenshotButton: React.FC<PropsType> = ({
cameraId,
timestamp,
}) => {
const { openModal, closeModal } = useModalSlice();
const { openNotification } = useNotificationSlice();

// Get total number of recent activities
const {
isLoading: isLoadingImage,
error: isErrorImage,
data: imageData,
refetch: fetchImage,
} = useQuery(
["recentActivitiesCount", cameraId],
getActivityImage(cameraId, timestamp),
{ enabled: false }
);

const onButtonClick = () => {
fetchImage();
};

useEffect(() => {
if (imageData) {
openModal({
title: timestamp,
modalContent: imageData.data,
isLoading: true,
});
}
}, [imageData]);

useEffect(() => {
if (isLoadingImage) {
openModal({
title: timestamp,
modalContent: "",
isLoading: true,
});
}
}, [isLoadingImage]);

useEffect(() => {
if (isErrorImage) {
openNotification({
type: "error",
message: "Could not fetch image.",
});
closeModal();
}
}, [isErrorImage]);

return (
<Button
toolTipText="View screenshot"
icon={<CameraOutlined />}
onClick={onButtonClick}
/>
);
};
1 change: 1 addition & 0 deletions Frontend/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { VideoRecordingScreen } from "./video-recording-screen/video-recording-screen";
export { Table } from "./table/table";
export { Button } from "./button/button";
export { ViewScreenshotButton } from "./button/view-screenshot";
export { Card } from "./card/card";
export { Input } from "./input/input";
2 changes: 1 addition & 1 deletion Frontend/src/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type PropsType = {

/** This component renders a input field */
export const Input = React.forwardRef<HTMLInputElement, PropsType>(
({ label, password = false, error = undefined, ...props }, ref) => {
({ label, password = false, error = undefined, ...props }, ref:any) => {
return (
<div className="py-1">
<div className={"font-bold pb-2"}>{label}</div>
Expand Down
2 changes: 1 addition & 1 deletion Frontend/src/components/table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Table as AntTable } from "antd";
import { AnyObject } from "@/types";

type PropsType<T extends AnyObject> = {
data: T[];
data: T[] | undefined;
columns: ColumnsType<T>;
pagination?: TablePaginationConfig;
loading?: boolean;
Expand Down
Loading

0 comments on commit 6f98680

Please sign in to comment.