async def create_logger(new_logger: SourceLoggerDTO, reboot_processor: Optional[bool] = True): """ Adds a logger. """ config_dict = extract_config() loggers_index = [int(x[-1]) for x in config_dict.keys() if x.startswith("SourceLogger_")] loggers = get_source_loggers() try: validate_logger(new_logger) except ValidationError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer(str(e)) ) if new_logger.name in [ps["name"] for ps in loggers]: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer("Logger already exists", error_type="config duplicated logger") ) logger_file = map_to_config_file_format(new_logger, True) index = 0 if loggers_index: index = max(loggers_index) + 1 config_dict[f"SourceLogger_{index}"] = logger_file success = update_config(config_dict, reboot_processor) if not success: return handle_response(logger_file, success, status.HTTP_201_CREATED) return next((ps for ps in get_source_loggers() if ps["name"] == logger_file["Name"]), None)
async def create_periodic_task(new_periodic_task: PeriodicTaskDTO, reboot_processor: Optional[bool] = True): """ Adds a periodic task. """ config_dict = extract_config() periodic_tasks_index = [ int(x[-1]) for x in config_dict.keys() if x.startswith("PeriodicTask_") ] periodic_tasks = get_periodic_tasks() try: validate_periodic_task(new_periodic_task) except ValidationError as e: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer(str(e))) if new_periodic_task.name in [ps["name"] for ps in periodic_tasks]: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Periodic task already exists", error_type="config duplicated periodic_task")) periodic_task_file = map_to_config_file_format(new_periodic_task, True) index = 0 if periodic_tasks_index: index = max(periodic_tasks_index) + 1 config_dict[f"PeriodicTask_{index}"] = periodic_task_file success = update_config(config_dict, reboot_processor) if not success: return handle_response(periodic_task_file, success, status.HTTP_201_CREATED) return next((ps for ps in get_periodic_tasks() if ps["name"] == periodic_task_file["Name"]), None)
async def create_camera(new_camera: CameraDTO, reboot_processor: Optional[bool] = True): """ Adds a new camera to the processor. """ config_dict = extract_config() cameras_name = [x for x in config_dict.keys() if x.startswith("Source_")] cameras = [map_camera(x, config_dict) for x in cameras_name] if new_camera.id is None: ids = [camera["id"] for camera in cameras] new_camera.id = str(get_first_unused_id(ids)) elif new_camera.id in [camera["id"] for camera in cameras]: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Camera already exists", error_type="config duplicated camera")) camera_dict = map_to_camera_file_format(new_camera) config_dict[f"Source_{len(cameras)}"] = camera_dict success = update_config(config_dict, reboot_processor) if not success: return handle_response(camera_dict, success, status.HTTP_201_CREATED) camera_screenshot_directory = os.path.join( os.environ.get("ScreenshotsDirectory"), new_camera.id) Path(camera_screenshot_directory).mkdir(parents=True, exist_ok=True) heatmap_directory = os.path.join(os.getenv("SourceLogDirectory"), new_camera.id, "objects_log") Path(heatmap_directory).mkdir(parents=True, exist_ok=True) return next( (camera for camera in get_cameras() if camera["id"] == camera_dict["Id"]), None)
async def edit_logger(logger_name: str, edited_logger: SourceLoggerDTO, reboot_processor: Optional[bool] = True): """ Edits the configuration related to the logger <logger_name> """ edited_logger.name = logger_name config_dict = extract_config() edited_logger_section = next(( key for key, value in config_dict.items() if key.startswith("SourceLogger_") and value["Name"] == logger_name ), None) if not edited_logger_section: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"The logger: {logger_name} does not exist") try: validate_logger(edited_logger) except ValidationError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer(str(e)) ) logger_file = map_to_config_file_format(edited_logger, True) config_dict[edited_logger_section] = logger_file success = update_config(config_dict, reboot_processor) if not success: return handle_response(logger_file, success) return next((ps for ps in get_source_loggers() if ps["name"] == logger_name), None)
async def edit_periodic_task(periodic_task_name: str, edited_periodic_task: PeriodicTaskDTO, reboot_processor: Optional[bool] = True): """ Edits the configuration related to the periodic task <periodic_task_name>. """ edited_periodic_task.name = periodic_task_name config_dict = extract_config() edited_periodic_task_section = next( (key for key, value in config_dict.items() if key.startswith("PeriodicTask_") and value["Name"] == periodic_task_name), None) if not edited_periodic_task_section: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"The periodic_task: {periodic_task_name} does not exist") try: validate_periodic_task(edited_periodic_task) except ValidationError as e: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer(str(e))) periodic_task_file = map_to_config_file_format(edited_periodic_task, True) config_dict[edited_periodic_task_section] = periodic_task_file success = update_config(config_dict, reboot_processor) if not success: return handle_response(periodic_task_file, success) return next( (ps for ps in get_periodic_tasks() if ps["name"] == periodic_task_name), None)
async def create_area(new_area: AreaConfigDTO, reboot_processor: Optional[bool] = True): """ Adds a new area to the processor. """ config_dict = extract_config() areas_name = [x for x in config_dict.keys() if x.startswith("Area_")] areas = [map_section_from_config(x, config_dict) for x in areas_name] if new_area.id in [area["id"] for area in areas]: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Area already exists", error_type="config duplicated area")) cameras = [x for x in config_dict.keys() if x.startswith("Source_")] cameras = [map_camera(x, config_dict, []) for x in cameras] camera_ids = [camera["id"] for camera in cameras] if not all(x in camera_ids for x in new_area.cameras.split(",")): non_existent_cameras = set( new_area.cameras.split(",")) - set(camera_ids) raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"The cameras: {non_existent_cameras} do not exist") area_dict = map_to_config_file_format(new_area) config_dict[f"Area_{len(areas)}"] = area_dict success = update_config(config_dict, reboot_processor) if not success: return handle_response(area_dict, success, status.HTTP_201_CREATED) return next( (area for area in get_areas() if area["id"] == area_dict["Id"]), None)
async def delete_area(area_id: str, reboot_processor: Optional[bool] = True): """ Deletes the configuration related to the area <area_id> """ if area_id.upper() == ALL_AREAS: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Area with ID: 'ALL' cannot be deleted.", error_type="Invalid ID")) config_dict = extract_config() areas_name = [x for x in config_dict.keys() if x.startswith("Area_")] areas = [map_section_from_config(x, config_dict) for x in areas_name] areas_ids = [area["id"] for area in areas] try: index = areas_ids.index(area_id) except ValueError: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"The area: {area_id} does not exist") config_dict.pop(f"Area_{index}") config_dict = reestructure_areas((config_dict)) success = update_config(config_dict, reboot_processor) area_directory = os.path.join(os.getenv("AreaLogDirectory"), area_id) shutil.rmtree(area_directory) return handle_response(None, success, status.HTTP_204_NO_CONTENT)
def validate_dates(from_date: date, to_date: date): if from_date > to_date: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Invalid range of dates", error_type="from_date doesn't come before to_date", loc=["query", "from_date"]))
async def create_user(auth_info: AuthDTO): """ Creates the API user (if it's not already created) with the given password. """ try: create_api_user(auth_info.user, auth_info.password) except Exception as e: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer(str(e)))
async def create_area(new_area: AreaConfigDTO, reboot_processor: Optional[bool] = True): """ Adds a new area to the processor. """ # TODO: We have to autogenerate the ID. config = get_config() areas = config.get_areas() if new_area.id in [area.id for area in areas]: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer("Area already exists", error_type="config duplicated area") ) elif new_area.id.upper() == ALL_AREAS: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer("Area with ID: 'ALL' is not valid.", error_type="Invalid ID") ) cameras = config.get_video_sources() camera_ids = [camera.id for camera in cameras] if not all(x in camera_ids for x in new_area.cameras.split(",")): non_existent_cameras = set(new_area.cameras.split(",")) - set(camera_ids) raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"The cameras: {non_existent_cameras} do not exist") occupancy_rules = new_area.occupancy_rules del new_area.occupancy_rules area_dict = map_to_config_file_format(new_area) config_dict = extract_config() config_dict[f"Area_{len(areas)-1}"] = area_dict success = update_config(config_dict, reboot_processor) if occupancy_rules: set_occupancy_rules(new_area.id, occupancy_rules) if not success: return handle_response(area_dict, success, status.HTTP_201_CREATED) area_directory = os.path.join(os.getenv("AreaLogDirectory"), new_area.id, "occupancy_log") Path(area_directory).mkdir(parents=True, exist_ok=True) area_config_directory = os.path.join(os.getenv("AreaConfigDirectory"), new_area.id) Path(area_config_directory).mkdir(parents=True, exist_ok=True) # known issue: Occupancy rules not returned return next((area for area in get_areas() if area["id"] == area_dict["Id"]), None)
def get_heatmap(camera_id: str, from_date: date = Query( (date.today() - timedelta(days=date.today().weekday(), weeks=4))), to_date: date = Query(date.today()), report_type: Optional[str] = "violations"): """ Returns a heatmap image displaying the violations/detections detected by the camera <camera_id> """ validate_camera_existence(camera_id) validate_dates(from_date, to_date) if report_type in ["violations", "detections"]: return generate_heatmap(camera_id, from_date, to_date, report_type) else: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Invalid report_type", error_type="invalid config"))
async def create_camera(new_camera: CameraDTO, reboot_processor: Optional[bool] = True): """ Adds a new camera to the processor. """ config_dict = extract_config() cameras_name = [x for x in config_dict.keys() if x.startswith("Source_")] cameras = [map_camera(x, config_dict) for x in cameras_name] if new_camera.id in [camera["id"] for camera in cameras]: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Camera already exists", error_type="config duplicated camera")) camera_dict = map_to_camera_file_format(new_camera) config_dict[f"Source_{len(cameras)}"] = camera_dict success = update_config(config_dict, reboot_processor) if not success: return handle_response(camera_dict, success, status.HTTP_201_CREATED) return next((camera for camera in get_cameras(["withImage"]) if camera["id"] == camera_dict["Id"]), None)
async def edit_area(area_id: str, edited_area: AreaConfigDTO, reboot_processor: Optional[bool] = True): """ Edits the configuration related to the area <area_id> """ if area_id.upper() == ALL_AREAS: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=bad_request_serializer( "Area with ID: 'ALL' cannot be edited.", error_type="Invalid ID")) edited_area.id = area_id config_dict = extract_config() area_names = [x for x in config_dict.keys() if x.startswith("Area_")] areas = [map_section_from_config(x, config_dict) for x in area_names] areas_ids = [area["id"] for area in areas] try: index = areas_ids.index(area_id) except ValueError: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"The area: {area_id} does not exist") cameras = [x for x in config_dict.keys() if x.startswith("Source_")] cameras = [map_camera(x, config_dict, []) for x in cameras] camera_ids = [camera["id"] for camera in cameras] if not all(x in camera_ids for x in edited_area.cameras.split(",")): non_existent_cameras = set( edited_area.cameras.split(",")) - set(camera_ids) raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"The cameras: {non_existent_cameras} do not exist") area_dict = map_to_config_file_format(edited_area) config_dict[f"Area_{index}"] = area_dict success = update_config(config_dict, reboot_processor) if not success: return handle_response(area_dict, success) return next((area for area in get_areas() if area["id"] == area_id), None)