From a9490da5a6b37ef3ce4d79710e6dfe67b90f82d9 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 31 May 2025 11:44:46 +0300 Subject: [PATCH 1/9] refactor code --- server/routers/kfu-m-24-1/sber_mobile/auth.js | 2 +- server/routers/kfu-m-24-1/sber_mobile/index.js | 2 +- server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/routers/kfu-m-24-1/sber_mobile/auth.js b/server/routers/kfu-m-24-1/sber_mobile/auth.js index 48e781a..39ef7bd 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/auth.js +++ b/server/routers/kfu-m-24-1/sber_mobile/auth.js @@ -1,5 +1,5 @@ const router = require('express').Router(); -const getSupabaseClient = require('./supabaseClient').getSupabaseClient; +const { getSupabaseClient } = require('./supabaseClient'); // POST /sign-in router.post('/sign-in', async (req, res) => { diff --git a/server/routers/kfu-m-24-1/sber_mobile/index.js b/server/routers/kfu-m-24-1/sber_mobile/index.js index c7e6553..be3d4d2 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/index.js @@ -1,6 +1,6 @@ const router = require('express').Router(); const authRouter = require('./auth'); -const supabaseRouter = require('./supabaseClient').router; +const { supabaseRouter } = require('./supabaseClient'); module.exports = router; diff --git a/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js b/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js index 0712909..bac0342 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js +++ b/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js @@ -34,5 +34,5 @@ try { module.exports = { getSupabaseClient, - router + supabaseRouter: router }; \ No newline at end of file From 539b1d2277b0c0892ceb6c1147846df694a68087 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 31 May 2025 19:13:39 +0300 Subject: [PATCH 2/9] add getting profile proto --- .../kfu-m-24-1/sber_mobile/users/index.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 server/routers/kfu-m-24-1/sber_mobile/users/index.js diff --git a/server/routers/kfu-m-24-1/sber_mobile/users/index.js b/server/routers/kfu-m-24-1/sber_mobile/users/index.js new file mode 100644 index 0000000..a32e262 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/users/index.js @@ -0,0 +1,28 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// POST /profile +router.get('/profile', async (req, res) => { + const { user_id } = req.body; + const supabase = getSupabaseClient(); + const { data, error } = await supabase.from('user_profiles').select(` + id, + full_name, + avatar_url, + updated_at, + auth.users(phone) + `).eq('id', user_id); + console.log('@@@@@@@@@@@@@@@@@@@@@@@@'); + console.log(data); + if (error) return res.status(400).json({ error: error.message }); + res.json({ + id: data.id, + username: data.full_name, + avatar_url: data.avatar_url, + phone: data.users.phone, + apartment: '9', + updated_at: data.updated_at + }); +}); + +module.exports = router; \ No newline at end of file From 36107afbc2c318e91e11a152266d6f72ec892cd4 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 31 May 2025 19:17:10 +0300 Subject: [PATCH 3/9] add router --- server/routers/kfu-m-24-1/sber_mobile/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/routers/kfu-m-24-1/sber_mobile/index.js b/server/routers/kfu-m-24-1/sber_mobile/index.js index be3d4d2..d645f49 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/index.js @@ -1,8 +1,10 @@ const router = require('express').Router(); const authRouter = require('./auth'); const { supabaseRouter } = require('./supabaseClient'); +const profileRouter = require('./users/index'); module.exports = router; -router.use('/auth', authRouter); -router.use('/supabase', supabaseRouter); \ No newline at end of file +router.use('/auth', authRouter); +router.use('/supabase', supabaseRouter); +router.use('', profileRouter); \ No newline at end of file From b5f6f6d30f76696129cebab5cc58191f4eeeb33e Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 31 May 2025 19:19:25 +0300 Subject: [PATCH 4/9] fix router --- server/routers/kfu-m-24-1/sber_mobile/users/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/kfu-m-24-1/sber_mobile/users/index.js b/server/routers/kfu-m-24-1/sber_mobile/users/index.js index a32e262..6aae4f3 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/users/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/users/index.js @@ -1,5 +1,5 @@ const router = require('express').Router(); -const { getSupabaseClient } = require('./supabaseClient'); +const { getSupabaseClient } = require('../supabaseClient'); // POST /profile router.get('/profile', async (req, res) => { From ca4bfdade4599ec5125afe8ca448f9c768c957fe Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 31 May 2025 19:27:45 +0300 Subject: [PATCH 5/9] change users --- server/routers/kfu-m-24-1/sber_mobile/users/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/kfu-m-24-1/sber_mobile/users/index.js b/server/routers/kfu-m-24-1/sber_mobile/users/index.js index 6aae4f3..673b873 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/users/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/users/index.js @@ -10,7 +10,7 @@ router.get('/profile', async (req, res) => { full_name, avatar_url, updated_at, - auth.users(phone) + users(phone) `).eq('id', user_id); console.log('@@@@@@@@@@@@@@@@@@@@@@@@'); console.log(data); From 8031938b2fd46feea7ca0d0c1a5c53006fcfefd2 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 31 May 2025 19:37:17 +0300 Subject: [PATCH 6/9] change request --- .../kfu-m-24-1/sber_mobile/users/index.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/server/routers/kfu-m-24-1/sber_mobile/users/index.js b/server/routers/kfu-m-24-1/sber_mobile/users/index.js index 673b873..45e16bf 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/users/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/users/index.js @@ -5,23 +5,21 @@ const { getSupabaseClient } = require('../supabaseClient'); router.get('/profile', async (req, res) => { const { user_id } = req.body; const supabase = getSupabaseClient(); - const { data, error } = await supabase.from('user_profiles').select(` + const { data, error } = await supabase.from('users').select(` id, - full_name, - avatar_url, - updated_at, - users(phone) + phone, + user_profiles(full_name,avatar_url,updated_at) `).eq('id', user_id); console.log('@@@@@@@@@@@@@@@@@@@@@@@@'); console.log(data); if (error) return res.status(400).json({ error: error.message }); res.json({ id: data.id, - username: data.full_name, - avatar_url: data.avatar_url, - phone: data.users.phone, + username: data.user_profiles.full_name, + avatar_url: data.user_profiles.avatar_url, + phone: data.phone, apartment: '9', - updated_at: data.updated_at + updated_at: data.user_profiles.updated_at }); }); From c251a640b652af7d3b5667b03402dab8e85ea68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B5=D0=B2=20=D0=9C?= =?UTF-8?q?=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=B5=D1=80=D0=B3=D0=B5?= =?UTF-8?q?=D0=B5=D0=B2=D0=B8=D1=87?= Date: Tue, 3 Jun 2025 12:24:19 +0300 Subject: [PATCH 7/9] add profile --- .../kfu-m-24-1/sber_mobile/get-constants.js | 7 +++ .../routers/kfu-m-24-1/sber_mobile/index.js | 2 +- .../routers/kfu-m-24-1/sber_mobile/profile.js | 54 +++++++++++++++++++ .../kfu-m-24-1/sber_mobile/supabaseClient.js | 5 +- .../kfu-m-24-1/sber_mobile/users/index.js | 26 --------- 5 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 server/routers/kfu-m-24-1/sber_mobile/profile.js delete mode 100644 server/routers/kfu-m-24-1/sber_mobile/users/index.js diff --git a/server/routers/kfu-m-24-1/sber_mobile/get-constants.js b/server/routers/kfu-m-24-1/sber_mobile/get-constants.js index 0834951..fba7807 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/get-constants.js +++ b/server/routers/kfu-m-24-1/sber_mobile/get-constants.js @@ -12,7 +12,14 @@ const getSupabaseKey = async () => { return data.features['sber_mobile'].SUPABASE_KEY.value; }; +const getSupabaseServiceKey = async () => { + const response = await fetch('https://admin.bro-js.ru/api/config/v1/dev'); + const data = await response.json(); + return data.features['sber_mobile'].SUPABASE_SERVICE_KEY.value; +}; + module.exports = { getSupabaseUrl, getSupabaseKey, + getSupabaseServiceKey }; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/index.js b/server/routers/kfu-m-24-1/sber_mobile/index.js index d645f49..f8dd26f 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/index.js @@ -1,7 +1,7 @@ const router = require('express').Router(); const authRouter = require('./auth'); const { supabaseRouter } = require('./supabaseClient'); -const profileRouter = require('./users/index'); +const profileRouter = require('./profile'); module.exports = router; diff --git a/server/routers/kfu-m-24-1/sber_mobile/profile.js b/server/routers/kfu-m-24-1/sber_mobile/profile.js new file mode 100644 index 0000000..cb4612a --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/profile.js @@ -0,0 +1,54 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// GET /profile +router.get('/profile', async (req, res) => { + const { user_id } = req.body; + const supabase = getSupabaseClient(); + let { data: userData, error: userError } = await supabase.auth.admin.getUserById(user_id); + + if (userError) return res.status(400).json({ error: userError.message }); + + let { data: profileData, error: profileError } = await supabase.from('user_profiles').select(` + id, + full_name, + avatar_url, + updated_at + `).eq('id', user_id).single(); + + if (profileError) return res.status(400).json({ error: profileError.message }); + + res.json({ + id: profileData.id, + username: profileData.full_name, + avatar_url: profileData.avatar_url, + phone: userData.user.phone, + apartment: '9', + updated_at: profileData.updated_at + }); +}); + +// POST /profile +router.post('/profile', async (req, res) => { + const { user_id, data } = req.body; + const supabase = getSupabaseClient(); + + const { data: userData, error: userError } = await supabase.auth.admin.updateUserById( + user_id, + { phone: data.phone } + ) + + if (userError) return res.status(400).json({ error: userError.message }); + + let { error: profileError } = await supabase.from('user_profiles').update({ + full_name: data.username, + avatar_url: data.avatar_url, + // apartment: data.apartment + }).eq('id', user_id).single(); + + if (profileError) return res.status(400).json({ error: profileError.message }); + + res.json({ success: true }); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js b/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js index bac0342..938cc18 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js +++ b/server/routers/kfu-m-24-1/sber_mobile/supabaseClient.js @@ -1,13 +1,14 @@ const router = require('express').Router(); const { createClient } = require('@supabase/supabase-js'); -const { getSupabaseUrl, getSupabaseKey } = require('./get-constants'); +const { getSupabaseUrl, getSupabaseKey, getSupabaseServiceKey } = require('./get-constants'); let supabase = null; async function initSupabaseClient() { const supabaseUrl = await getSupabaseUrl(); const supabaseAnonKey = await getSupabaseKey(); - supabase = createClient(supabaseUrl, supabaseAnonKey); + const supabaseServiceRoleKey = await getSupabaseServiceKey(); + supabase = createClient(supabaseUrl, supabaseServiceRoleKey); } function getSupabaseClient() { diff --git a/server/routers/kfu-m-24-1/sber_mobile/users/index.js b/server/routers/kfu-m-24-1/sber_mobile/users/index.js deleted file mode 100644 index 45e16bf..0000000 --- a/server/routers/kfu-m-24-1/sber_mobile/users/index.js +++ /dev/null @@ -1,26 +0,0 @@ -const router = require('express').Router(); -const { getSupabaseClient } = require('../supabaseClient'); - -// POST /profile -router.get('/profile', async (req, res) => { - const { user_id } = req.body; - const supabase = getSupabaseClient(); - const { data, error } = await supabase.from('users').select(` - id, - phone, - user_profiles(full_name,avatar_url,updated_at) - `).eq('id', user_id); - console.log('@@@@@@@@@@@@@@@@@@@@@@@@'); - console.log(data); - if (error) return res.status(400).json({ error: error.message }); - res.json({ - id: data.id, - username: data.user_profiles.full_name, - avatar_url: data.user_profiles.avatar_url, - phone: data.phone, - apartment: '9', - updated_at: data.user_profiles.updated_at - }); -}); - -module.exports = router; \ No newline at end of file From ea691536ac5bb9330d0ac2413a1dedfd5e6facef Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 4 Jun 2025 18:49:25 +0300 Subject: [PATCH 8/9] add db api --- .../sber_mobile/additional_services.js | 56 ++++++++++++ .../kfu-m-24-1/sber_mobile/apartments.js | 14 +++ .../kfu-m-24-1/sber_mobile/buildings.js | 14 +++ .../routers/kfu-m-24-1/sber_mobile/cameras.js | 28 ++++++ .../routers/kfu-m-24-1/sber_mobile/chats.js | 28 ++++++ .../routers/kfu-m-24-1/sber_mobile/index.js | 26 +++++- .../kfu-m-24-1/sber_mobile/initiatives.js | 90 +++++++++++++++++++ .../kfu-m-24-1/sber_mobile/messages.js | 14 +++ .../routers/kfu-m-24-1/sber_mobile/profile.js | 14 +++ .../routers/kfu-m-24-1/sber_mobile/tickets.js | 14 +++ .../kfu-m-24-1/sber_mobile/user_apartments.js | 18 ++++ .../sber_mobile/utility_payments.js | 17 ++++ .../routers/kfu-m-24-1/sber_mobile/votes.js | 44 +++++++++ 13 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 server/routers/kfu-m-24-1/sber_mobile/additional_services.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/apartments.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/buildings.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/cameras.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/chats.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/messages.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/tickets.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/user_apartments.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/utility_payments.js create mode 100644 server/routers/kfu-m-24-1/sber_mobile/votes.js diff --git a/server/routers/kfu-m-24-1/sber_mobile/additional_services.js b/server/routers/kfu-m-24-1/sber_mobile/additional_services.js new file mode 100644 index 0000000..1861a60 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/additional_services.js @@ -0,0 +1,56 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все дополнительные сервисы (по УК) +router.get('/additional-services', async (req, res) => { + const supabase = getSupabaseClient(); + const { management_company_id } = req.query; + let query = supabase.from('additional_services').select('*'); + if (management_company_id) query = query.eq('management_company_id', management_company_id); + const { data, error } = await query; + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Получить сервис по id +router.get('/additional-services/:id', async (req, res) => { + const supabase = getSupabaseClient(); + const { id } = req.params; + const { data, error } = await supabase.from('additional_services').select('*').eq('id', id).single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Создать сервис +router.post('/additional-services', async (req, res) => { + const supabase = getSupabaseClient(); + const { title, description, category, price, image_url } = req.body; + const { data, error } = await supabase.from('additional_services').insert([ + { title, description, category, price, image_url } + ]).select().single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Обновить сервис +router.put('/additional-services/:id', async (req, res) => { + const supabase = getSupabaseClient(); + const { id } = req.params; + const { title, description, category, price, image_url } = req.body; + const { data, error } = await supabase.from('additional_services').update({ + title, description, category, price, image_url + }).eq('id', id).select().single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Удалить сервис +router.delete('/additional-services/:id', async (req, res) => { + const supabase = getSupabaseClient(); + const { id } = req.params; + const { error } = await supabase.from('additional_services').delete().eq('id', id); + if (error) return res.status(400).json({ error: error.message }); + res.json({ success: true }); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/apartments.js b/server/routers/kfu-m-24-1/sber_mobile/apartments.js new file mode 100644 index 0000000..5182e78 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/apartments.js @@ -0,0 +1,14 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все квартиры по дому +router.get('/apartments', async (req, res) => { + const supabase = getSupabaseClient(); + const { building_id } = req.query; + if (!building_id) return res.status(400).json({ error: 'building_id required' }); + const { data, error } = await supabase.from('apartments').select('*').eq('building_id', building_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/buildings.js b/server/routers/kfu-m-24-1/sber_mobile/buildings.js new file mode 100644 index 0000000..8230923 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/buildings.js @@ -0,0 +1,14 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все дома по УК +router.get('/buildings', async (req, res) => { + const supabase = getSupabaseClient(); + const { management_company_id } = req.query; + if (!management_company_id) return res.status(400).json({ error: 'management_company_id required' }); + const { data, error } = await supabase.from('buildings').select('*').eq('management_company_id', management_company_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/cameras.js b/server/routers/kfu-m-24-1/sber_mobile/cameras.js new file mode 100644 index 0000000..1425b9f --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/cameras.js @@ -0,0 +1,28 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все камеры по дому +router.get('/cameras', async (req, res) => { + const supabase = getSupabaseClient(); + const { building_id } = req.query; + if (!building_id) return res.status(400).json({ error: 'building_id required' }); + const { data, error } = await supabase.from('cameras').select('*').eq('building_id', building_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Получить все камеры по квартире (через building_id) +router.get('/cameras/by-apartment', async (req, res) => { + const supabase = getSupabaseClient(); + const { apartment_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id required' }); + // Получаем building_id квартиры и сразу камеры этого дома + const { data, error } = await supabase + .from('cameras') + .select('*, apartments!inner(id, building_id)') + .eq('apartments.id', apartment_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/chats.js b/server/routers/kfu-m-24-1/sber_mobile/chats.js new file mode 100644 index 0000000..983f0dd --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/chats.js @@ -0,0 +1,28 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все чаты по дому +router.get('/chats', async (req, res) => { + const supabase = getSupabaseClient(); + const { building_id } = req.query; + if (!building_id) return res.status(400).json({ error: 'building_id required' }); + const { data, error } = await supabase.from('chats').select('*').eq('building_id', building_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Получить все чаты по квартире (через building_id) +router.get('/chats/by-apartment', async (req, res) => { + const supabase = getSupabaseClient(); + const { apartment_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id required' }); + // Получаем building_id квартиры и сразу чаты этого дома + const { data, error } = await supabase + .from('chats') + .select('*, apartments!inner(id, building_id)') + .eq('apartments.id', apartment_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/index.js b/server/routers/kfu-m-24-1/sber_mobile/index.js index f8dd26f..5c4af66 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/index.js @@ -2,9 +2,33 @@ const router = require('express').Router(); const authRouter = require('./auth'); const { supabaseRouter } = require('./supabaseClient'); const profileRouter = require('./profile'); +const initiativesRouter = require('./initiatives'); +const votesRouter = require('./votes'); +const paymentServicesRouter = require('./payment_services'); +const additionalServicesRouter = require('./additional_services'); +const chatsRouter = require('./chats'); +const camerasRouter = require('./cameras'); +const ticketsRouter = require('./tickets'); +const messagesRouter = require('./messages'); +const utilityPaymentsRouter = require('./utility_payments'); +const apartmentsRouter = require('./apartments'); +const buildingsRouter = require('./buildings'); +const userApartmentsRouter = require('./user_apartments'); module.exports = router; router.use('/auth', authRouter); router.use('/supabase', supabaseRouter); -router.use('', profileRouter); \ No newline at end of file +router.use('', profileRouter); +router.use('', initiativesRouter); +router.use('', votesRouter); +router.use('', paymentServicesRouter); +router.use('', additionalServicesRouter); +router.use('', chatsRouter); +router.use('', camerasRouter); +router.use('', ticketsRouter); +router.use('', messagesRouter); +router.use('', utilityPaymentsRouter); +router.use('', apartmentsRouter); +router.use('', buildingsRouter); +router.use('', userApartmentsRouter); \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives.js b/server/routers/kfu-m-24-1/sber_mobile/initiatives.js new file mode 100644 index 0000000..4e0469b --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/initiatives.js @@ -0,0 +1,90 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все инициативы (по дому) +router.get('/initiatives', async (req, res) => { + const supabase = getSupabaseClient(); + const { building_id } = req.query; + let query = supabase.from('initiatives').select('*'); + if (building_id) query = query.eq('building_id', building_id); + const { data, error } = await query; + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Получить инициативу по id (и optionally building_id) +router.get('/initiatives/:id', async (req, res) => { + const supabase = getSupabaseClient(); + const { id } = req.params; + const { building_id } = req.query; + let query = supabase.from('initiatives').select('*').eq('id', id); + if (building_id) query = query.eq('building_id', building_id); + const { data, error } = await query.single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Создать инициативу +router.post('/initiatives', async (req, res) => { + const supabase = getSupabaseClient(); + const { building_id, creator_id, title, description, status, target_amount, image_url } = req.body; + const { data, error } = await supabase.from('initiatives').insert([ + { building_id, creator_id, title, description, status, target_amount, image_url } + ]).select().single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Обновить инициативу +router.put('/initiatives/:id', async (req, res) => { + const supabase = getSupabaseClient(); + const { id } = req.params; + const { title, description, status, target_amount, current_amount, image_url } = req.body; + const { data, error } = await supabase.from('initiatives').update({ + title, description, status, target_amount, current_amount, image_url + }).eq('id', id).select().single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Удалить инициативу +router.delete('/initiatives/:id', async (req, res) => { + const supabase = getSupabaseClient(); + const { id } = req.params; + const { error } = await supabase.from('initiatives').delete().eq('id', id); + if (error) return res.status(400).json({ error: error.message }); + res.json({ success: true }); +}); + +// Получить все инициативы по квартире с голосами пользователя +router.get('/initiatives/by-apartment', async (req, res) => { + const supabase = getSupabaseClient(); + const { apartment_id, user_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id required' }); + // Получаем building_id квартиры + const { data: apartments, error: err1 } = await supabase + .from('apartments') + .select('building_id') + .eq('id', apartment_id) + .single(); + if (err1) return res.status(400).json({ error: err1.message }); + const building_id = apartments.building_id; + // Получаем инициативы этого дома с голосами пользователя (если user_id передан) + let selectStr = '*, votes:initiatives(id, votes!left(user_id, vote_type))'; + if (!user_id) selectStr = '*'; + const { data, error } = await supabase + .from('initiatives') + .select(selectStr) + .eq('building_id', building_id); + if (error) return res.status(400).json({ error: error.message }); + // Если user_id передан, фильтруем только голос текущего пользователя + if (user_id && data) { + data.forEach(initiative => { + initiative.user_vote = (initiative.votes || []).find(v => v.user_id === user_id) || null; + delete initiative.votes; + }); + } + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/messages.js b/server/routers/kfu-m-24-1/sber_mobile/messages.js new file mode 100644 index 0000000..b1a8188 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/messages.js @@ -0,0 +1,14 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все сообщения в чате +router.get('/messages', async (req, res) => { + const supabase = getSupabaseClient(); + const { chat_id } = req.query; + if (!chat_id) return res.status(400).json({ error: 'chat_id required' }); + const { data, error } = await supabase.from('messages').select('*').eq('chat_id', chat_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/profile.js b/server/routers/kfu-m-24-1/sber_mobile/profile.js index cb4612a..09c97c6 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/profile.js +++ b/server/routers/kfu-m-24-1/sber_mobile/profile.js @@ -51,4 +51,18 @@ router.post('/profile', async (req, res) => { res.json({ success: true }); }); +// Получить управляющую компанию по квартире +router.get('/management-company', async (req, res) => { + const supabase = getSupabaseClient(); + const { apartment_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id required' }); + const { data: apartment, error: err1 } = await supabase.from('apartments').select('building_id').eq('id', apartment_id).single(); + if (err1) return res.status(400).json({ error: err1.message }); + const { data: building, error: err2 } = await supabase.from('buildings').select('management_company_id').eq('id', apartment.building_id).single(); + if (err2) return res.status(400).json({ error: err2.message }); + const { data: company, error: err3 } = await supabase.from('management_companies').select('*').eq('id', building.management_company_id).single(); + if (err3) return res.status(400).json({ error: err3.message }); + res.json(company); +}); + module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/tickets.js b/server/routers/kfu-m-24-1/sber_mobile/tickets.js new file mode 100644 index 0000000..5ff082d --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/tickets.js @@ -0,0 +1,14 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все тикеты по дому +router.get('/tickets', async (req, res) => { + const supabase = getSupabaseClient(); + const { building_id } = req.query; + if (!building_id) return res.status(400).json({ error: 'building_id required' }); + const { data, error } = await supabase.from('tickets').select('*').eq('building_id', building_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/user_apartments.js b/server/routers/kfu-m-24-1/sber_mobile/user_apartments.js new file mode 100644 index 0000000..e5421ba --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/user_apartments.js @@ -0,0 +1,18 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все квартиры пользователя +router.get('/user-apartments', async (req, res) => { + const supabase = getSupabaseClient(); + const { user_id } = req.query; + if (!user_id) return res.status(400).json({ error: 'user_id required' }); + const { data: links, error: err1 } = await supabase.from('apartment_residents').select('apartment_id').eq('user_id', user_id); + if (err1) return res.status(400).json({ error: err1.message }); + const apartmentIds = links.map(l => l.apartment_id); + if (!apartmentIds.length) return res.json([]); + const { data, error } = await supabase.from('apartments').select('*').in('id', apartmentIds); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js b/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js new file mode 100644 index 0000000..a6e8b98 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js @@ -0,0 +1,17 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все платежи по конкретной квартире с данными сервиса +router.get('/utility-payments', async (req, res) => { + const supabase = getSupabaseClient(); + const { apartment_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id required' }); + const { data, error } = await supabase + .from('utility_payments') + .select('*, payment_services(*)') + .eq('apartment_id', apartment_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/votes.js b/server/routers/kfu-m-24-1/sber_mobile/votes.js new file mode 100644 index 0000000..d46df22 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/votes.js @@ -0,0 +1,44 @@ +const router = require('express').Router(); +const { getSupabaseClient } = require('./supabaseClient'); + +// Получить все голоса по инициативе +router.get('/votes/:initiative_id', async (req, res) => { + const supabase = getSupabaseClient(); + const { initiative_id } = req.params; + const { data, error } = await supabase.from('votes').select('*').eq('initiative_id', initiative_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Получить голос пользователя по инициативе +router.get('/votes/:initiative_id/:user_id', async (req, res) => { + const supabase = getSupabaseClient(); + const { initiative_id, user_id } = req.params; + const { data, error } = await supabase.from('votes').select('*').eq('initiative_id', initiative_id).eq('user_id', user_id).single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Получить все голоса по инициативе (через query) +router.get('/votes', async (req, res) => { + const supabase = getSupabaseClient(); + const { initiative_id } = req.query; + if (!initiative_id) return res.status(400).json({ error: 'initiative_id required' }); + const { data, error } = await supabase.from('votes').select('*').eq('initiative_id', initiative_id); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +// Проголосовать (создать или обновить голос) +router.post('/votes', async (req, res) => { + const supabase = getSupabaseClient(); + const { initiative_id, user_id, vote_type } = req.body; + // upsert: если голос уже есть, обновить, иначе создать + const { data, error } = await supabase.from('votes').upsert([ + { initiative_id, user_id, vote_type } + ], { onConflict: ['initiative_id', 'user_id'] }).select().single(); + if (error) return res.status(400).json({ error: error.message }); + res.json(data); +}); + +module.exports = router; \ No newline at end of file From 0500497fc108b1e10b89dfdc0e72393ebbb3b932 Mon Sep 17 00:00:00 2001 From: DenAntonov Date: Sat, 7 Jun 2025 00:48:51 +0300 Subject: [PATCH 9/9] fix api and add apartment info --- .../kfu-m-24-1/sber_mobile/DB_Scheme.txt | 222 ++++++++++++++++++ .../kfu-m-24-1/sber_mobile/apartments.js | 31 +++ .../routers/kfu-m-24-1/sber_mobile/index.js | 2 - .../routers/kfu-m-24-1/sber_mobile/profile.js | 3 +- 4 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt diff --git a/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt b/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt new file mode 100644 index 0000000..81dade2 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt @@ -0,0 +1,222 @@ +-- Расширение для генерации UUID +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +-- 1. Управляющие компании +CREATE TABLE management_companies ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + logo_url TEXT, + contact_phone TEXT NOT NULL, + email TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 2. Жилые дома +CREATE TABLE buildings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + management_company_id UUID NOT NULL REFERENCES management_companies(id), + name TEXT, + address TEXT NOT NULL, + floors INTEGER, + entrances INTEGER, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 3. Профили пользователей +CREATE TABLE user_profiles ( + id UUID PRIMARY KEY REFERENCES auth.users(id), + full_name TEXT, + avatar_url TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 4. Квартиры +CREATE TABLE apartments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + building_id UUID NOT NULL REFERENCES buildings(id), + number TEXT NOT NULL, + area DECIMAL(10, 2), + floor INTEGER, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5. Связь пользователей с квартирами +CREATE TABLE apartment_residents ( + apartment_id UUID NOT NULL REFERENCES apartments(id), + user_id UUID NOT NULL REFERENCES auth.users(id), + is_owner BOOLEAN DEFAULT FALSE, + created_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (apartment_id, user_id) +); + +-- 6. Сервисы УК +CREATE TABLE management_services ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + management_company_id UUID NOT NULL REFERENCES management_companies(id), + title TEXT NOT NULL, + description TEXT, + category TEXT NOT NULL, + base_price DECIMAL(10, 2), + image_url TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 7. Связь сервисов УК с домами +CREATE TABLE building_management_services ( + building_id UUID NOT NULL REFERENCES buildings(id), + service_id UUID NOT NULL REFERENCES management_services(id), + custom_price DECIMAL(10, 2), + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (building_id, service_id) +); + +-- 8. Платежные сервисы +CREATE TABLE payment_services ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + logo_url TEXT, + provider_name TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 9. Дополнительные сервисы +CREATE TABLE additional_services ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title TEXT NOT NULL, + description TEXT, + category TEXT NOT NULL, + price DECIMAL(10, 2), + image_url TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 10. Инициативы +CREATE TABLE initiatives ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + building_id UUID NOT NULL REFERENCES buildings(id), + creator_id UUID NOT NULL REFERENCES auth.users(id), + title TEXT NOT NULL, + description TEXT NOT NULL, + status TEXT NOT NULL CHECK ( + status IN ('moderation', 'review', 'fundraising', 'approved', 'rejected') + ), + target_amount DECIMAL(10, 2), + current_amount DECIMAL(10, 2) DEFAULT 0, + image_url TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 11. Голосования +CREATE TABLE votes ( + initiative_id UUID NOT NULL REFERENCES initiatives(id), + user_id UUID NOT NULL REFERENCES auth.users(id), + vote_type TEXT NOT NULL CHECK (vote_type IN ('for', 'against')), + created_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (initiative_id, user_id) +); + +-- 12. Чат +CREATE TABLE chats ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + building_id UUID NOT NULL REFERENCES buildings(id), + name TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 13. Сообщения +CREATE TABLE messages ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + chat_id UUID NOT NULL REFERENCES chats(id), + user_id UUID NOT NULL REFERENCES auth.users(id), + text TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 14. Камеры +CREATE TABLE cameras ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + building_id UUID NOT NULL REFERENCES buildings(id), + location TEXT NOT NULL, + stream_url TEXT NOT NULL, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 15. Платежи ЖКХ (исправленная версия) +CREATE TABLE utility_payments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + apartment_id UUID NOT NULL REFERENCES apartments(id), + service_id UUID NOT NULL REFERENCES payment_services(id), + amount DECIMAL(10, 2) NOT NULL, + period DATE NOT NULL, + status TEXT NOT NULL CHECK (status IN ('paid', 'pending', 'overdue')), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 16. Заявки +CREATE TABLE tickets ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES auth.users(id), + building_id UUID NOT NULL REFERENCES buildings(id), + title TEXT NOT NULL, + description TEXT NOT NULL, + status TEXT NOT NULL CHECK (status IN ('open', 'in_progress', 'resolved')), + category TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Индексы +CREATE INDEX idx_buildings_management_company ON buildings(management_company_id); +CREATE INDEX idx_management_services_company ON management_services(management_company_id); +CREATE INDEX idx_building_services_building ON building_management_services(building_id); +CREATE INDEX idx_initiatives_building ON initiatives(building_id); +CREATE INDEX idx_votes_initiative ON votes(initiative_id); +CREATE INDEX idx_messages_chat ON messages(chat_id); +CREATE INDEX idx_cameras_building ON cameras(building_id); +CREATE INDEX idx_tickets_user ON tickets(user_id); +CREATE INDEX idx_apartments_building ON apartments(building_id); +CREATE INDEX idx_apartment_residents_apartment ON apartment_residents(apartment_id); +CREATE INDEX idx_apartment_residents_user ON apartment_residents(user_id); +CREATE INDEX idx_payments_apartment ON utility_payments(apartment_id); +CREATE INDEX idx_payments_service ON utility_payments(service_id); + +-- Триггеры для обновления updated_at +CREATE OR REPLACE FUNCTION update_updated_at() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Применяем триггеры ко всем таблицам с updated_at +DO $$ +DECLARE + t record; +BEGIN + FOR t IN + SELECT table_name + FROM information_schema.columns + WHERE column_name = 'updated_at' + AND table_schema = 'public' + LOOP + EXECUTE format('CREATE TRIGGER trigger_%s_updated_at + BEFORE UPDATE ON %I + FOR EACH ROW EXECUTE FUNCTION update_updated_at()', + t.table_name, t.table_name); + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/apartments.js b/server/routers/kfu-m-24-1/sber_mobile/apartments.js index 5182e78..fd360ef 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/apartments.js +++ b/server/routers/kfu-m-24-1/sber_mobile/apartments.js @@ -11,4 +11,35 @@ router.get('/apartments', async (req, res) => { res.json(data); }); +// Получить адрес квартиры и название дома по id квартиры +router.get('/apartment-info', async (req, res) => { + const supabase = getSupabaseClient(); + const { apartment_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id required' }); + + // Получаем квартиру с building_id и номером + const { data: apartment, error: err1 } = await supabase + .from('apartments') + .select('id, number, building_id') + .eq('id', apartment_id) + .single(); + if (err1) return res.status(400).json({ error: err1.message }); + + // Получаем дом по building_id + const { data: building, error: err2 } = await supabase + .from('buildings') + .select('id, name, address') + .eq('id', apartment.building_id) + .single(); + if (err2) return res.status(400).json({ error: err2.message }); + + res.json({ + apartment_id: apartment.id, + apartment_number: apartment.number, + building_id: building.id, + building_name: building.name, + building_address: building.address + }); +}); + module.exports = router; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/index.js b/server/routers/kfu-m-24-1/sber_mobile/index.js index 5c4af66..ea0ca85 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/index.js +++ b/server/routers/kfu-m-24-1/sber_mobile/index.js @@ -4,7 +4,6 @@ const { supabaseRouter } = require('./supabaseClient'); const profileRouter = require('./profile'); const initiativesRouter = require('./initiatives'); const votesRouter = require('./votes'); -const paymentServicesRouter = require('./payment_services'); const additionalServicesRouter = require('./additional_services'); const chatsRouter = require('./chats'); const camerasRouter = require('./cameras'); @@ -22,7 +21,6 @@ router.use('/supabase', supabaseRouter); router.use('', profileRouter); router.use('', initiativesRouter); router.use('', votesRouter); -router.use('', paymentServicesRouter); router.use('', additionalServicesRouter); router.use('', chatsRouter); router.use('', camerasRouter); diff --git a/server/routers/kfu-m-24-1/sber_mobile/profile.js b/server/routers/kfu-m-24-1/sber_mobile/profile.js index 09c97c6..982a17e 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/profile.js +++ b/server/routers/kfu-m-24-1/sber_mobile/profile.js @@ -3,7 +3,7 @@ const { getSupabaseClient } = require('./supabaseClient'); // GET /profile router.get('/profile', async (req, res) => { - const { user_id } = req.body; + const { user_id } = req.query; const supabase = getSupabaseClient(); let { data: userData, error: userError } = await supabase.auth.admin.getUserById(user_id); @@ -23,7 +23,6 @@ router.get('/profile', async (req, res) => { username: profileData.full_name, avatar_url: profileData.avatar_url, phone: userData.user.phone, - apartment: '9', updated_at: profileData.updated_at }); });