From 6aa4d6c098324cd5350705dc3c8d24f8c410a600 Mon Sep 17 00:00:00 2001 From: inexcode Date: Sun, 30 Oct 2022 11:29:52 +0000 Subject: [PATCH] Students --- {contacts => backend}/__init__.py | 0 {contacts => backend}/app.py | 6 +- {contacts => backend}/db.py | 0 {contacts => backend}/schema.sql | 19 +-- contacts/contacts.py => backend/students.py | 147 ++++++++---------- frontend/src/App.jsx | 45 +++--- .../{ContactDialog.jsx => StudentDialog.jsx} | 104 ++++--------- requirements.txt | 2 + 8 files changed, 129 insertions(+), 194 deletions(-) rename {contacts => backend}/__init__.py (100%) rename {contacts => backend}/app.py (77%) rename {contacts => backend}/db.py (100%) rename {contacts => backend}/schema.sql (71%) rename contacts/contacts.py => backend/students.py (63%) rename frontend/src/{ContactDialog.jsx => StudentDialog.jsx} (50%) diff --git a/contacts/__init__.py b/backend/__init__.py similarity index 100% rename from contacts/__init__.py rename to backend/__init__.py diff --git a/contacts/app.py b/backend/app.py similarity index 77% rename from contacts/app.py rename to backend/app.py index b67b15d..2bbf281 100644 --- a/contacts/app.py +++ b/backend/app.py @@ -3,7 +3,7 @@ import os from . import db -from .contacts import Contacts, Contact +from .students import Students, Student from flask import Flask, request, jsonify from flask_restful import Api @@ -15,8 +15,8 @@ def create_app(test_config=None): db.init_app(app) api = Api(app) CORS(app, resources={r"/api/*": {"origins": "*"}}) - api.add_resource(Contacts, '/api/contacts') - api.add_resource(Contact, '/api/contacts/') + api.add_resource(Students, '/api/students') + api.add_resource(Student, '/api/students/') return app diff --git a/contacts/db.py b/backend/db.py similarity index 100% rename from contacts/db.py rename to backend/db.py diff --git a/contacts/schema.sql b/backend/schema.sql similarity index 71% rename from contacts/schema.sql rename to backend/schema.sql index 4823b55..18b3323 100644 --- a/contacts/schema.sql +++ b/backend/schema.sql @@ -2,7 +2,7 @@ DROP TABLE IF EXISTS main; DROP TABLE IF EXISTS first_name; DROP TABLE IF EXISTS last_name; DROP TABLE IF EXISTS middle_name; -DROP TABLE IF EXISTS street; +DROP TABLE IF EXISTS discipline; CREATE TABLE first_name ( first_name_id SERIAL PRIMARY KEY, first_name_val VARCHAR(255) NOT NULL @@ -15,23 +15,20 @@ CREATE TABLE middle_name ( middle_name_id SERIAL PRIMARY KEY, middle_name_val VARCHAR(255) NOT NULL ); -CREATE TABLE street ( - street_id SERIAL PRIMARY KEY, - street_val VARCHAR(255) NOT NULL +CREATE TABLE discipline ( + discipline_id SERIAL PRIMARY KEY, + discipline_val VARCHAR(255) NOT NULL ); CREATE TABLE main ( uid serial, last_name int, first_name int, middle_name int, - street int, - build VARCHAR(255), - build_k VARCHAR(255), - apartment VARCHAR(255), - telephone VARCHAR(255) NOT NULL, + discipline int, + mark VARCHAR(255), CONSTRAINT fk_last_name FOREIGN KEY (last_name) REFERENCES last_name(last_name_id), CONSTRAINT fk_first_name FOREIGN KEY (first_name) REFERENCES first_name(first_name_id), CONSTRAINT fk_middle_name FOREIGN KEY (middle_name) REFERENCES middle_name(middle_name_id), - CONSTRAINT fk_street FOREIGN KEY (street) REFERENCES street(street_id), + CONSTRAINT fk_discipline FOREIGN KEY (discipline) REFERENCES discipline(discipline_id), PRIMARY KEY (uid) -); \ No newline at end of file +); diff --git a/contacts/contacts.py b/backend/students.py similarity index 63% rename from contacts/contacts.py rename to backend/students.py index eaa98ee..1c819c3 100644 --- a/contacts/contacts.py +++ b/backend/students.py @@ -8,31 +8,28 @@ from flask_restful import Resource, Api, reqparse from .db import get_db -class Contacts(Resource): +class Students(Resource): def get(self): db = get_db() cur = db.cursor() - cur.execute("SELECT uid, last_name_val, first_name_val, middle_name_val, street_val, build, build_k, apartment, telephone" + cur.execute("SELECT uid, last_name_val, first_name_val, middle_name_val, discipline_val, mark" " FROM main" " join last_name on main.last_name = last_name_id" " join first_name on main.first_name = first_name_id" " join middle_name on main.middle_name = middle_name_id" - " join street on main.street = street_id") - contacts = cur.fetchall() + " join discipline on main.discipline = discipline_id") + students = cur.fetchall() def convert(data): return { 'uid': data[0], 'last_name': data[1], 'first_name': data[2], 'middle_name': data[3], - 'street': data[4], - 'build': data[5], - 'build_k': data[6], - 'apartment': data[7], - 'telephone': data[8] + 'discipline': data[4], + 'mark': data[5] } - contacts = [convert(contact) for contact in contacts] - return contacts + students = [convert(student) for student in students] + return students def post(self): db = get_db() @@ -41,13 +38,10 @@ class Contacts(Resource): parser.add_argument('last_name') parser.add_argument('first_name') parser.add_argument('middle_name') - parser.add_argument('street') - parser.add_argument('build') - parser.add_argument('build_k') - parser.add_argument('apartment') - parser.add_argument('telephone', required=True) + parser.add_argument('discipline') + parser.add_argument('mark') args = parser.parse_args() - + cur.execute("SELECT uid FROM main ORDER BY uid DESC LIMIT 1") uid = cur.fetchone() if uid is None: @@ -84,83 +78,77 @@ class Contacts(Resource): middle_name = middle_name[0] else: middle_name = middle_name[0] - - cur.execute("SELECT street_id FROM street WHERE street_val = %s", (args['street'],)) - street = cur.fetchone() - if street is None: - cur.execute("INSERT INTO street (street_val) VALUES (%s)", (args['street'],)) - cur.execute("SELECT street_id FROM street WHERE street_val = %s", (args['street'],)) - street = cur.fetchone() - street = street[0] - else: - street = street[0] - cur.execute("INSERT INTO main (uid, last_name, first_name, middle_name, street, build, build_k, apartment, telephone)" - " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)", - (uid, last_name, first_name, middle_name, street, args['build'], args['build_k'], args['apartment'], args['telephone'])) - + cur.execute("SELECT discipline_id FROM discipline WHERE discipline_val = %s", (args['discipline'],)) + discipline = cur.fetchone() + if discipline is None: + cur.execute("INSERT INTO discipline (discipline_val) VALUES (%s)", (args['discipline'],)) + cur.execute("SELECT discipline_id FROM discipline WHERE discipline_val = %s", (args['discipline'],)) + discipline = cur.fetchone() + discipline = discipline[0] + else: + discipline = discipline[0] + + cur.execute("INSERT INTO main (uid, last_name, first_name, middle_name, discipline, mark)" + " VALUES (%s, %s, %s, %s, %s, %s)", + (uid, last_name, first_name, middle_name, discipline, args['mark'])) + db.commit() return {'uid': uid}, 201 -class Contact(Resource): +class Student(Resource): def get(self, uid): db = get_db() cur = db.cursor() - cur.execute("SELECT uid, last_name_val, first_name_val, middle_name_val, street_val, build, build_k, apartment, telephone" + cur.execute("SELECT uid, last_name_val, first_name_val, middle_name_val, discipline_val, mark" " FROM main" " join last_name on main.last_name = last_name_id" " join first_name on main.first_name = first_name_id" " join middle_name on main.middle_name = middle_name_id" - " join street on main.street = street_id" + " join discipline on main.discipline = discipline_id" " WHERE uid = %s", (uid,)) - contact = cur.fetchone() - if contact is None: - return {'message': 'Contact not found'}, 404 + student = cur.fetchone() + if student is None: + return {'message': 'Student not found'}, 404 def convert(data): return { 'uid': data[0], 'last_name': data[1], 'first_name': data[2], 'middle_name': data[3], - 'street': data[4], - 'build': data[5], - 'build_k': data[6], - 'apartment': data[7], - 'telephone': data[8] + 'discipline': data[4], + 'mark': data[5] } - contact = convert(contact) - return contact + student = convert(student) + return student def delete(self, uid): db = get_db() cur = db.cursor() cur.execute("SELECT uid FROM main WHERE uid = %s", (uid,)) - contact = cur.fetchone() - if contact is None: - return {'message': 'Contact not found'}, 404 + student = cur.fetchone() + if student is None: + return {'message': 'Student not found'}, 404 cur.execute("DELETE FROM main WHERE uid = %s", (uid,)) db.commit() - return {'message': 'Contact deleted'} + return {'message': 'Student deleted'} def put(self, uid): parser = reqparse.RequestParser() parser.add_argument('last_name') parser.add_argument('first_name') parser.add_argument('middle_name') - parser.add_argument('street') - parser.add_argument('build') - parser.add_argument('build_k') - parser.add_argument('apartment') - parser.add_argument('telephone') + parser.add_argument('discipline') + parser.add_argument('mark') args = parser.parse_args() db = get_db() cur = db.cursor() cur.execute("SELECT uid FROM main WHERE uid = %s", (uid,)) - contact = cur.fetchone() - if contact is None: - return {'message': 'Contact not found'}, 404 - + student = cur.fetchone() + if student is None: + return {'message': 'Student not found'}, 404 + if args['last_name'] is not None: cur.execute("SELECT last_name_id FROM last_name WHERE last_name_val = %s", (args['last_name'],)) last_name = cur.fetchone() @@ -172,7 +160,7 @@ class Contact(Resource): else: last_name = last_name[0] cur.execute("UPDATE main SET last_name = %s WHERE uid = %s", (last_name, uid)) - + if args['first_name'] is not None: cur.execute("SELECT first_name_id FROM first_name WHERE first_name_val = %s", (args['first_name'],)) first_name = cur.fetchone() @@ -184,7 +172,7 @@ class Contact(Resource): else: first_name = first_name[0] cur.execute("UPDATE main SET first_name = %s WHERE uid = %s", (first_name, uid)) - + if args['middle_name'] is not None: cur.execute("SELECT middle_name_id FROM middle_name WHERE middle_name_val = %s", (args['middle_name'],)) middle_name = cur.fetchone() @@ -196,30 +184,21 @@ class Contact(Resource): else: middle_name = middle_name[0] cur.execute("UPDATE main SET middle_name = %s WHERE uid = %s", (middle_name, uid)) - - if args['street'] is not None: - cur.execute("SELECT street_id FROM street WHERE street_val = %s", (args['street'],)) - street = cur.fetchone() - if street is None: - cur.execute("INSERT INTO street (street_val) VALUES (%s)", (args['street'],)) - cur.execute("SELECT street_id FROM street WHERE street_val = %s", (args['street'],)) - street = cur.fetchone() - street = street[0] - else: - street = street[0] - cur.execute("UPDATE main SET street = %s WHERE uid = %s", (street, uid)) - - if args['build'] is not None: - cur.execute("UPDATE main SET build = %s WHERE uid = %s", (args['build'], uid)) - if args['build_k'] is not None: - cur.execute("UPDATE main SET build_k = %s WHERE uid = %s", (args['build_k'], uid)) - - if args['apartment'] is not None: - cur.execute("UPDATE main SET apartment = %s WHERE uid = %s", (args['apartment'], uid)) - - if args['telephone'] is not None: - cur.execute("UPDATE main SET telephone = %s WHERE uid = %s", (args['telephone'], uid)) - + if args['discipline'] is not None: + cur.execute("SELECT discipline_id FROM discipline WHERE discipline_val = %s", (args['discipline'],)) + discipline = cur.fetchone() + if discipline is None: + cur.execute("INSERT INTO discipline (discipline_val) VALUES (%s)", (args['discipline'],)) + cur.execute("SELECT discipline_id FROM discipline WHERE discipline_val = %s", (args['discipline'],)) + discipline = cur.fetchone() + discipline = discipline[0] + else: + discipline = discipline[0] + cur.execute("UPDATE main SET discipline = %s WHERE uid = %s", (discipline, uid)) + + if args['mark'] is not None: + cur.execute("UPDATE main SET mark = %s WHERE uid = %s", (args['mark'], uid)) + db.commit() - return {'message': 'Contact updated'} \ No newline at end of file + return {'message': 'Student updated'} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 28a1d85..89dae98 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -4,38 +4,31 @@ import { Container, Dialog, Typography, IconButton, Tooltip } from '@mui/materia import MUIDataTable from "mui-datatables"; import { useAxios } from './axios'; import { useMutation, useQuery, useQueryClient } from 'react-query'; -import ContactDialog from './ContactDialog'; +import StudentDialog from './StudentDialog'; import AddIcon from '@mui/icons-material/Add'; function App() { const client = useAxios(); const queryClient = useQueryClient() const [open, setOpen] = React.useState(false); - const [openedContact, setOpenedContact] = React.useState({}); - const { data, status } = useQuery('contacts', async () => { - const {data} = await client.get('/api/contacts'); - return data.map(({ + const [openedStudent, setOpenedStudent] = React.useState({}); + const { data, status } = useQuery('students', async () => { + const {data} = await client.get('/api/students'); + return data.map(({ uid, first_name, last_name, middle_name, - telephone, - street, - build, - build_k, - apartment + discipline, + mark, }) => { return { 'first_name': first_name, 'last_name': last_name, 'middle_name': middle_name, - 'telephone': telephone, - 'street': street, - 'build': build, - 'build_k': build_k, - 'apartment': apartment, + 'discipline': discipline, + 'mark': mark, 'display_name': `${first_name} ${last_name} ${middle_name}`, - 'display_address': `${street} ${build} ${build_k} ${apartment}`, 'uid': uid }; }) @@ -50,23 +43,23 @@ function App() { name: "display_name", label: "Имя" }, { - name: "telephone", label: "Телефон" + name: "mark", label: "Оценка" }, { - name: "display_address", label: "Адрес" + name: "discipline", label: "Дисциплина" }, ]; const commitDelete = useMutation(async (uid) => { - await client.delete(`/api/contacts/${uid}`); + await client.delete(`/api/students/${uid}`); }, { onSuccess: () => { - queryClient.invalidateQueries('contacts'); + queryClient.invalidateQueries('students'); } }); const handleRowClick = (rowData) => { - setOpenedContact(data.find(({uid}) => uid === rowData[0])); + setOpenedStudent(data.find(({uid}) => uid === rowData[0])); setOpen(true); console.log(data.find(({uid}) => uid === rowData[0])); }; @@ -88,7 +81,7 @@ function App() { return ( - ); function CustomToolbar() { if (data !== undefined) return ( - + { - setOpenedContact({}); + setOpenedStudent({}); setOpen(true); }}> diff --git a/frontend/src/ContactDialog.jsx b/frontend/src/StudentDialog.jsx similarity index 50% rename from frontend/src/ContactDialog.jsx rename to frontend/src/StudentDialog.jsx index 01b2bce..165182c 100644 --- a/frontend/src/ContactDialog.jsx +++ b/frontend/src/StudentDialog.jsx @@ -6,35 +6,32 @@ import { useAxios } from './axios'; import { useMutation, useQuery, useQueryClient } from 'react-query'; -function ContactDialog({ +function StudentDialog({ open, onClose, - contact, + student, }) { const client = useAxios(); const queryClient = useQueryClient() - const [uid, setUid] = React.useState(contact ? contact.uid : null); - const [firstName, setFirstName] = React.useState(contact['first_name'] ?? ''); - const [lastName, setLastName] = React.useState(contact['last_name'] ?? ''); - const [middleName, setMiddleName] = React.useState(contact['middle_name'] ?? ''); - const [telephone, setTelephone] = React.useState(contact['telephone'] ?? ''); - const [street, setStreet] = React.useState(contact['street'] ?? ''); - const [build, setBuild] = React.useState(contact['build'] ?? ''); - const [buildK, setBuildK] = React.useState(contact['build_k'] ?? ''); - const [apartment, setApartment] = React.useState(contact['apartment'] ?? ''); + const [uid, setUid] = React.useState(student ? student.uid : null); + const [firstName, setFirstName] = React.useState(student['first_name'] ?? ''); + const [lastName, setLastName] = React.useState(student['last_name'] ?? ''); + const [middleName, setMiddleName] = React.useState(student['middle_name'] ?? ''); + const [discipline, setDiscipline] = React.useState(student['discipline'] ?? ''); + const [mark, setMark] = React.useState(student['mark'] ?? ''); - const commitCreate = useMutation(async (payload) => client.post('/api/contacts', payload), { + const commitCreate = useMutation(async (payload) => client.post('/api/students', payload), { onSuccess: () => { - queryClient.invalidateQueries('contacts'); + queryClient.invalidateQueries('students'); onClose(); } }); - const commitUpdate = useMutation(async (payload) => client.put(`/api/contacts/${contact['uid']}`, payload), { + const commitUpdate = useMutation(async (payload) => client.put(`/api/students/${student['uid']}`, payload), { onSuccess: () => { - queryClient.invalidateQueries('contacts'); - queryClient.invalidateQueries(['contact', contact['uid']]); + queryClient.invalidateQueries('students'); + queryClient.invalidateQueries(['student', student['uid']]); onClose(); } }); @@ -45,13 +42,10 @@ function ContactDialog({ first_name: firstName, last_name: lastName, middle_name: middleName, - telephone: telephone, - street: street, - build: build, - build_k: buildK, - apartment: apartment + discipline: discipline, + mark: mark, }; - if (contact['uid']) { + if (student['uid']) { commitUpdate.mutate(data); } else { @@ -61,16 +55,13 @@ function ContactDialog({ }; const loadData = () => { - console.log(contact); - setUid(contact['uid'] ?? null); - setFirstName(contact['first_name'] ?? ''); - setLastName(contact['last_name'] ?? ''); - setMiddleName(contact['middle_name'] ?? ''); - setTelephone(contact['telephone'] ?? ''); - setStreet(contact['street'] ?? ''); - setBuild(contact['build'] ?? ''); - setBuildK(contact['build_k'] ?? ''); - setApartment(contact['apartment'] ?? ''); + console.log(student); + setUid(student['uid'] ?? null); + setFirstName(student['first_name'] ?? ''); + setLastName(student['last_name'] ?? ''); + setMiddleName(student['middle_name'] ?? ''); + setDiscipline(student['discipline'] ?? ''); + setMark(student['mark'] ?? ''); }; return ( @@ -83,7 +74,7 @@ function ContactDialog({ onEnter: loadData }} > - Контакт + Студент
@@ -116,47 +107,20 @@ function ContactDialog({ setTelephone(event.target.value)} + id="discipline" + label="Дисциплина" + value={discipline} + onChange={(event) => setDiscipline(event.target.value)} fullWidth required /> - + setStreet(event.target.value)} - fullWidth - /> - - - setBuild(event.target.value)} - fullWidth - /> - - - setBuildK(event.target.value)} - fullWidth - /> - - - setApartment(event.target.value)} + id="mark" + label="Оценка" + value={mark} + onChange={(event) => setMark(event.target.value)} fullWidth /> @@ -172,4 +136,4 @@ function ContactDialog({ ); } -export default ContactDialog; +export default StudentDialog; diff --git a/requirements.txt b/requirements.txt index 620619a..495d9cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ flask flask_restful flask_socketio +flask_cors pytz +click psycopg2