Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding events routes #2

Merged
merged 1 commit into from
Oct 24, 2023
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
coverage.cobertura.xml

# nyc test coverage
.nyc_output
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"eslint": "eslint ./src",
"eslint_fix": "eslint ./src --fix",
"test": "env TS_NODE_TRANSPILE_ONLY=true mocha -r ts-node/register 'tests/**/**.test.ts' --timeout 180000 --exit",
"coverage": "env TS_NODE_TRANSPILE_ONLY=true nyc --reporter=html --reporter=text -- mocha -r ts-node/register 'tests/**/**.test.ts' --timeout 180000 --exit",
"coverage": "env TS_NODE_TRANSPILE_ONLY=true nyc --reporter=html --reporter=text -- mocha -r ts-node/register 'tests/**/**.test.ts' --timeout 180000 --exit && nyc report --reporter=cobertura && mv ./coverage/cobertura-coverage.xml ./coverage.cobertura.xml",
"devops_coverage": "env TS_NODE_TRANSPILE_ONLY=true nyc -- mocha -r ts-node/register 'tests/**/**.test.ts' --reporter ./tests/assets/multiple_reporters.js --timeout 180000 --exit",
"generate_cobertura": "nyc report --reporter=cobertura"
},
Expand Down
167 changes: 167 additions & 0 deletions src/controllers/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { WatchList, watchLists } from "./watch-lists";

function randomCharacters(length: number) {
let result = '';
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}

interface FeatureConfidence {
name: string | number;
confidence: number;
}

interface EventFace {
episode: number;
matched_object: string,
matched_cluster: null,
matched_card: null,
temperature: null,
created_date: string,
camera: number,
camera_group: number,
case: null,
thumbnail: string,
fullframe: string,
bs_type: "overall",
frame_coords_left: number,
frame_coords_top: number,
frame_coords_right: number,
frame_coords_bottom: number,
matched: boolean,
confidence: number,
cluster_confidence: number;
quality: number,
acknowledged_date: string,
acknowledged_by: number,
acknowledged_reaction: string,
acknowledged: boolean,
video_archive: null,
external_detector: boolean,
meta: object,
id: string,
looks_like_confidence: null,
matched_lists: number[],
detector_params: {
quality: number,
track: {
id: null;
};
},
features: {
headpose_yaw: FeatureConfidence,
headpose_pitch: FeatureConfidence,
beard: FeatureConfidence,
glasses: FeatureConfidence,
age: FeatureConfidence,
gender: FeatureConfidence,
medmask: FeatureConfidence,
emotions: FeatureConfidence;
},
verbose_matched_lists: WatchList[];
// TODO: once camera is implemented, bring it here
verbose_camera: object;
// TODO: once camera group is implemented, bring it here
verbose_camera_group: object;
}

let eventId = 0;
const events: { [eventId: number]: EventFace | undefined; } = {};

function createEvent({ created_date, camera }: { created_date?: string; camera: number; }) {
eventId++;

if (!created_date) {
created_date = new Date().toISOString();
}

const date = new Date(created_date);

const eventFace: EventFace = {
id: String(eventId),
episode: eventId,
created_date: created_date,
acknowledged_date: created_date,
camera: camera,
camera_group: 1,
thumbnail: `http://localhost:5000/uploads/${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}/face_event/${eventId}_face_thumbnail_${randomCharacters(6)}.jpg`,
fullframe: `http://localhost:5000/uploads/${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}/face_event/${eventId}_face_full_frame_${randomCharacters(6)}.jpg`,
matched_object: "",
matched_cluster: null,
matched_card: null,
temperature: null,
case: null,
bs_type: "overall",
frame_coords_left: 11,
frame_coords_top: 21,
frame_coords_right: 62,
frame_coords_bottom: 83,
matched: false,
acknowledged: true,
acknowledged_by: 0,
acknowledged_reaction: "",
cluster_confidence: 0.0,
confidence: 0.0,
external_detector: true,
looks_like_confidence: null,
matched_lists: [watchLists[0].id],
meta: {},
quality: 0.79995,
video_archive: null,
features: {
headpose_yaw: {
name: 22.01571,
confidence: 1
},
headpose_pitch: {
name: -15.91327,
confidence: 1
},
beard: {
name: "beard",
confidence: 0.894003
},
glasses: {
name: "none",
confidence: 0.988431
},
age: {
name: 33.0,
confidence: 1
},
gender: {
name: "male",
confidence: 0.999998
},
medmask: {
name: "none",
confidence: 0.999999
},
emotions: {
name: "neutral",
confidence: 0.97469
}
},
detector_params: {
quality: 0.79995084,
track: {
id: null
}
},
verbose_matched_lists: [watchLists[0]],
// TODO: once camera is implemented, bring it here
verbose_camera: {},
// TODO: once camera group is implemented, bring it here
verbose_camera_group: {}
};
events[eventId] = eventFace;
return eventFace;
}

export { createEvent };
71 changes: 71 additions & 0 deletions src/controllers/watch-lists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
interface WatchList {
id: number,
created_date: string,
modified_date: string,
active: boolean,
name: string,
comment: string,
color: string,
notify: boolean,
acknowledge: boolean,
camera_groups: [],
face_threshold: null,
body_threshold: null,
car_threshold: null,
ignore_events: boolean,
send_events_to_external_vms: boolean,
active_after: null,
active_before: null,
disable_schedule: object,
recount_schedule_on: null,
origin: "ffsecurity";
}

const watchLists: WatchList[] = [
{
"id": -1,
"created_date": "2023-09-02T15:49:23.312899Z",
"modified_date": "2023-09-02T15:49:23.312914Z",
"active": true,
"name": "Unmatched",
"comment": "Default list for unmatched events",
"color": "ffffff",
"notify": false,
"acknowledge": false,
"camera_groups": [],
"face_threshold": null,
"body_threshold": null,
"car_threshold": null,
"ignore_events": false,
"send_events_to_external_vms": false,
"active_after": null,
"active_before": null,
"disable_schedule": {},
"recount_schedule_on": null,
"origin": "ffsecurity"
},
{
"id": 1,
"created_date": "2023-09-02T15:49:23.306322Z",
"modified_date": "2023-09-02T15:49:23.306413Z",
"active": true,
"name": "Default Watch List",
"comment": "",
"color": "123456",
"notify": false,
"acknowledge": false,
"camera_groups": [],
"face_threshold": null,
"body_threshold": null,
"car_threshold": null,
"ignore_events": false,
"send_events_to_external_vms": false,
"active_after": null,
"active_before": null,
"disable_schedule": {},
"recount_schedule_on": null,
"origin": "ffsecurity"
}
];

export { watchLists, WatchList };
9 changes: 2 additions & 7 deletions src/routes/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ const upload = multer({

function loadDetectRoutes(app: Express) {

app.post('/detect/', validAuthorization, upload.any(), async (req: Request, res: Response) => {
app.post('/detect/', validAuthorization, upload.single('photo'), async (req: Request, res: Response) => {

let photo;
const photo = req.file;

if (!('attributes' in req.body)) {
return res.status(400).json({
Expand All @@ -21,11 +21,6 @@ function loadDetectRoutes(app: Express) {
});
}

if (req.files) {
const files = req.files as Express.Multer.File[];
photo = files.find((file) => file.fieldname == "photo");
}

if (!photo) {
return res.status(400).json({
"traceback": "",
Expand Down
96 changes: 96 additions & 0 deletions src/routes/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Express, Request, Response } from 'express';
import multer from 'multer';
import { validAuthorization } from '../services/route_middlewares';
import { createEvent } from '../controllers/events';

const upload = multer({
storage: multer.memoryStorage()
});

function loadEventsRoutes(app: Express) {

app.post('/events/faces/add/', validAuthorization, upload.single('fullframe'), async (req: Request, res: Response) => {

if (!('token' in req.body)) {
return res.status(400).json({
"traceback": "",
"code": "BAD_PARAM",
"desc": "This field is required.",
"param": "token"
});
}

if (!('camera' in req.body)) {
return res.status(400).json({
"traceback": "",
"code": "BAD_PARAM",
"desc": "This field is required.",
"param": "camera"
});
}

if (!('mf_selector' in req.body)) {
return res.status(400).json({
"traceback": "",
"code": "BAD_PARAM",
"desc": "This field is required.",
"param": "mf_selector"
});
}

const fullframe = req.file;

if (!fullframe) {
return res.status(400).json({
"traceback": "",
"code": "BAD_PARAM",
"desc": "No file was submitted.",
"param": "fullframe"
});
}

// TODO: implement token validation
// return res.status(403).json({
// "traceback": "",
// "code": "PERMISSION_DENIED",
// "desc": "Incorrect events creation API token"
// });

// TODO: implement camera_id validation
// return res.status(400).json({
// "traceback": "",
// "code": "BAD_PARAM",
// "desc": `Invalid pk "${req.body.camera}" - object does not exist.`,
// "param": "camera"
// });

// TODO: implement no face on fullframe
// return res.status(200).json({
// "orientation": 1,
// "objects": {
// }
// });

const eventFace = createEvent({
camera: req.body.camera,
created_date: req.body.timestamp
});

return res.status(200).json({
"events": [
eventFace.id
],
"errors": []
});
});

app.get('/events/faces/', validAuthorization, async (req: Request, res: Response) => {
return res.status(200).json({
"next_page": null,
"count": 0,
"results": []
});
});
}

export { loadEventsRoutes };
Loading