Commit cd2fe6f4 authored by Mikhail Sennikov's avatar Mikhail Sennikov
Browse files

Groups sketch

parent 0703e32b
No related merge requests found
Showing with 267 additions and 62 deletions
+267 -62
......@@ -6,6 +6,7 @@ from database import db_connection as db
from database.repositories.cam_groups import GroupRepository
from database.repositories.users import UserRepository
from database.schemas.cam_groups import GroupFull, GroupBase
from database.schemas.cams import CamOut
db_cam_groups_router = APIRouter()
......@@ -23,7 +24,7 @@ async def list_groups(
@db_cam_groups_router.get("/{group_id}", response_model=GroupFull)
async def get_groups(
async def get_group(
group_id: int,
group_repo: GroupRepository = Depends(db.get_repository(GroupRepository))
):
......@@ -76,6 +77,19 @@ async def delete_group(
return group
@db_cam_groups_router.get("/{group_id}/cams", response_model=List[CamOut], tags=["Cams"])
async def list_cams_in_group(
group_id: int,
group_repo: GroupRepository = Depends(db.get_repository(GroupRepository))
):
group = await group_repo.get(group_id)
if group is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND
)
return await group_repo.list_cams_in_group(group)
@db_cam_groups_router.get("/user/{user_id}", response_model=List[GroupFull], tags=["Users"])
async def list_user_groups(
user_id: int,
......
......@@ -5,6 +5,7 @@ from fastapi import APIRouter, HTTPException, status, Depends
from database import db_connection as db
from database.repositories.cam_groups import GroupRepository
from database.repositories.cams import CamRepository
from database.schemas.cam_groups import GroupFull
from database.schemas.cams import CamOut, CamCreate, CamUpdate
db_cams_router = APIRouter()
......@@ -76,7 +77,7 @@ async def delete_cam(
return cam
@db_cams_router.get("/{cam_id}/groups", response_model=List[CamOut], tags=["Cam groups"])
@db_cams_router.get("/{cam_id}/groups", response_model=List[GroupFull], tags=["Cam groups"])
async def list_cam_groups(
cam_id: int,
cam_repo: CamRepository = Depends(db.get_repository(CamRepository))
......@@ -90,7 +91,7 @@ async def list_cam_groups(
return groups
@db_cams_router.post("/{cam_id}/groups", response_model=CamOut, tags=["Cam groups"])
@db_cams_router.post("/{cam_id}/groups", response_model=GroupFull, tags=["Cam groups"])
async def add_cam_group(
cam_id: int,
group_id: int,
......@@ -103,7 +104,7 @@ async def add_cam_group(
return group
@db_cams_router.delete("/{cam_id}/groups", response_model=CamOut, tags=["Cam groups"])
@db_cams_router.delete("/{cam_id}/groups", response_model=GroupFull, tags=["Cam groups"])
async def delete_cam_group(
cam_id: int,
group_id: int,
......
......@@ -22,7 +22,7 @@ async def list_roles(
@db_roles_router.get("/{role_id}", response_model=RoleFull)
async def get_roles(
async def get_role(
role_id: int,
role_repo: RoleRepository = Depends(db.get_repository(RoleRepository))
):
......
......@@ -8,7 +8,7 @@ class Cam(Base):
id: Column = Column(Integer, primary_key=True) # Will make SERIAL
name: Column = Column(String, unique=True, nullable=False)
host: Column = Column(String, nullable=False)
port: Column = Column(Integer, unique=True, nullable=False)
port: Column = Column(Integer, unique=False, nullable=False)
username: Column = Column(String, nullable=False)
password: Column = Column(String, nullable=False)
......
......@@ -4,7 +4,7 @@ from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from database.models.auth import User
from database.models.cams import Group, UserInGroup
from database.models.cams import Group, UserInGroup, Cam, CamInGroup
from database.repositories.base import Repository
from database.schemas.cam_groups import GroupBase
......@@ -45,6 +45,12 @@ class GroupRepository(Repository):
await self._session.commit()
return group_db_obj
async def list_cams_in_group(self, group: Group) -> List[Cam]:
query = select(Cam).join(CamInGroup, CamInGroup.cam_id == Cam.id)
query = query.filter(CamInGroup.group_id == group.id)
cams_db_obj = await self._session.execute(query)
return [cam for cam, in cams_db_obj]
async def get_user_groups(self, user: User) -> List[Group]:
query = select(Group).join(UserInGroup, UserInGroup.group_id == Group.id)
query = query.filter(UserInGroup.user_id == user.id)
......
......@@ -45,7 +45,7 @@ class CamRepository(Repository):
return cam_db_obj
async def get_cam_groups(self, cam: Cam) -> List[Group]:
query = select(Group).join(CamInGroup, CamInGroup.cam_id == Cam.id)
query = select(Group).join(CamInGroup, CamInGroup.cam_id == Group.id)
query = query.filter(CamInGroup.cam_id == cam.id)
groups_db_obj = await self._session.execute(query)
return [group for group, in groups_db_obj]
......
......@@ -6,6 +6,7 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse, RedirectResponse
from database import db_connection
from database.api import db_router
from onvif_proxy import cams_connection
from onvif_proxy.onvif_proxy import onvif_router
......@@ -15,10 +16,10 @@ from proxy_switch.proxy_switch import switch_router
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['*']
)
# app.add_middleware(
# CORSMiddleware,
# allow_origins=['*']
# )
app.include_router(
onvif_router,
......@@ -55,6 +56,7 @@ rtsp_task = None
@app.on_event("startup")
async def startup_event():
await db_connection.create_models()
global rtsp_task
rtsp_task = asyncio.create_task(start_rtsp_server())
......
aiohttp
alembic
asyncpg
bcrypt
fastapi
lxml
onvif-zeep-async
......
......@@ -8,19 +8,20 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.2",
"@fortawesome/fontawesome-free": "^6.5.1",
"bootstrap": "^5.3.2",
"sass": "^1.69.3",
"sass": "^1.69.5",
"sass-loader": "^13.3.2",
"vue": "^3.3.4"
"vue": "^3.3.11",
"axios": "^1.6.2"
},
"devDependencies": {
"@babel/core": "^7.23.3",
"@babel/core": "^7.23.6",
"@babel/eslint-parser": "^7.23.3",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"eslint": "^8.54.0",
"eslint-plugin-vue": "^9.18.1"
"eslint": "^8.55.0",
"eslint-plugin-vue": "^9.19.2"
},
"eslintConfig": {
"root": true,
......
......@@ -3,7 +3,8 @@
<NavBar id="navbar"/>
<div class="content-wrapper">
<!-- <component :is="currentComponent"/>-->
<Gallery/>
<!-- <CamsList/>-->
<GroupsList/>
</div>
<Footer/>
</div>
......@@ -11,13 +12,15 @@
<script>
import NavBar from './components/NavBar.vue'
import Gallery from './components/Gallery.vue'
import CamsList from './components/CamsList.vue'
import Footer from './components/Footer.vue'
import GroupsList from "@/components/GroupsList.vue";
export default {
name: 'App',
components: {
Gallery,
GroupsList,
CamsList,
NavBar,
Footer
},
......
<template>
<div class="group-container">
<h2>{{group_name}}</h2>
<Gallery class=""
:cams="cams"
:active_cam_id="active_id"/>
</div>
</template>
<script>
import axios from "axios";
import Gallery from "@/components/Gallery.vue";
export default {
/* eslint-disable */
name: 'CamGroup',
components: {Gallery},
inject: ['Gallery'],
props: {
group_id: {
required: true
},
group_name: {
required: false
},
active_id: {
required: false
}
},
mounted() {
setInterval(this.fetchCams, 3000)
},
data() {
return {
cams: []
};
},
created() {
this.fetchCams();
},
methods: {
fetchCams() {
axios.get(`/db/cam_groups/${this.group_id}/cams`, {
headers: {
'Content-Type': 'application/json',
}
})
.then(response => {
this.cams = response.data;
})
.catch(error => {
console.error('Cams loading error:', error);
});
}
}
}
</script>
<style scoped>
.group-container {
border-bottom: 1px solid var(--light-color);
}
h2 {
margin: 0.5rem;
padding: 0.5rem 0;
color: var(--white-color);
background-color: var(--light-color);
border: none;
border-radius: var(--bs-border-radius);
}
</style>
......@@ -60,7 +60,8 @@ export default {
chooseCamera() {
fetch(`/switch/choose_camera/${this.camera_id}`,
{ method: 'POST', mode: 'no-cors' })
this.Gallery.update_active_cam()
// TODO
// this.Gallery.update_active_cam()
}
}
}
......
<template>
<Gallery class=""
:cams="cams"
:active_cam_id="active_cam"/>
</template>
<script>
import Gallery from "@/components/Gallery.vue";
export default {
/* eslint-disable */
name: 'CamsList',
components: {
Gallery
},
data() {
return {
cams: [],
active_cam: -1
}
},
methods: {
update_active_cam() {
fetch("/switch/active_cam", { method: 'GET' })
.then(
response => {
if (response.ok) {
response.json().then(data => {
this.active_cam = data
})
}
else if (response.status === 503) {
this.active_cam = -1
}
},
error => {
console.error("There was an error!", error);
});
}
},
mounted() {
fetch("/switch/cams", { method: 'GET' })
.then(
response => {
if (response.ok) {
response.json().then(json => {
this.cams = json
})
}
},
error => {
console.error("There was an error!", error);
});
setInterval(this.update_active_cam, 1000)
}
}
</script>
<style scoped>
</style>
......@@ -5,7 +5,7 @@
:camera_id="index"
:camera_name="camera.name"
:host="camera.host"
:active_id="active_cam"/>
:active_id="active_cam_id"/>
</div>
</div>
</template>
......@@ -19,50 +19,18 @@ export default {
components: {
CameraPreview
},
data() {
return {
cams: [],
active_cam: -1
props: {
cams: {
required: true
},
active_cam_id: {
required: false
}
},
provide() {
return {
Gallery: this
}
},
methods: {
update_active_cam() {
fetch("/switch/active_cam", { method: 'GET' })
.then(
response => {
if (response.ok) {
response.json().then(data => {
this.active_cam = data
})
}
else if (response.status === 503) {
this.active_cam = -1
}
},
error => {
console.error("There was an error!", error);
});
}
},
mounted() {
fetch("/switch/cams", { method: 'GET' })
.then(
response => {
if (response.ok) {
response.json().then(json => {
this.cams = json
})
}
},
error => {
console.error("There was an error!", error);
});
setInterval(this.update_active_cam, 1000)
}
}
</script>
......@@ -71,7 +39,8 @@ export default {
.cams-container {
display: grid;
padding: 3rem;
padding: 0;
margin: 0;
justify-items: center;
grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
grid-auto-rows: 19rem;
......
<template>
<div class="groups-container">
<div v-for="group in groups">
<CamGroup :group_id="group.id"
:group_name="group.name"/>
</div>
</div>
</template>
<script>
import CamGroup from "@/components/CamGroup.vue";
export default {
/* eslint-disable */
name: 'GroupsList',
components: {
CamGroup
},
data() {
return {
groups: [],
active_group: -1
}
},
methods: {
update_groups() {
fetch("/db/cam_groups/list", { method: 'GET' })
.then(
response => {
if (response.ok) {
response.json().then(json => {
this.groups = json
})
}
},
error => {
console.error("There was an error!", error);
});
}
},
mounted() {
this.update_groups()
setInterval(this.update_groups, 1000)
}
}
</script>
<style scoped>
.groups-container {
margin: 1rem 3rem;
}
</style>
module.exports = {
pluginOptions: {
i18n: {
locale: 'ru',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: true
}
},
devServer: {
proxy: {
'^/assets': {
target: `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 8080}`,
changeOrigin: true
},
'^/(?!ws)': {
target: 'http://localhost:9000',
changeOrigin: true
}
}
}
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment