simonov nikita lab 3 done
This commit is contained in:
parent
60ef5724cd
commit
f5b175e1fe
37
simonov_nikita_lab_3/docker-compose.yaml
Normal file
37
simonov_nikita_lab_3/docker-compose.yaml
Normal file
@ -0,0 +1,37 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
geodata-service:
|
||||
build:
|
||||
context: ./geodata_service
|
||||
ports:
|
||||
- "5001:5001"
|
||||
networks:
|
||||
- my_network
|
||||
restart: always
|
||||
|
||||
user-service:
|
||||
build:
|
||||
context: ./user_service
|
||||
ports:
|
||||
- "5002:5002"
|
||||
networks:
|
||||
- my_network
|
||||
restart: always
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- geodata-service
|
||||
- user-service
|
||||
networks:
|
||||
- my_network
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
my_network:
|
||||
driver: bridge
|
6
simonov_nikita_lab_3/geodata_service/Dockerfile
Normal file
6
simonov_nikita_lab_3/geodata_service/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
FROM python:3.11
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . /app
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5001", "geodata_service:app"]
|
70
simonov_nikita_lab_3/geodata_service/geo_service.py
Normal file
70
simonov_nikita_lab_3/geodata_service/geo_service.py
Normal file
@ -0,0 +1,70 @@
|
||||
from flask import Flask, jsonify, render_template, request, redirect, url_for
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///geodata.db'
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
class GeoData(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
location = db.Column(db.String(50), nullable=False)
|
||||
latitude = db.Column(db.Float, nullable=False)
|
||||
longitude = db.Column(db.Float, nullable=False)
|
||||
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
geodata = GeoData.query.all()
|
||||
return render_template('index.html', geodata=geodata)
|
||||
|
||||
@app.route('/add', methods=['POST'])
|
||||
def add():
|
||||
location = request.form['location']
|
||||
latitude = float(request.form['latitude'])
|
||||
longitude = float(request.form['longitude'])
|
||||
|
||||
new_geodata = GeoData(location=location, latitude=latitude, longitude=longitude)
|
||||
db.session.add(new_geodata)
|
||||
db.session.commit()
|
||||
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app.route('/update/<int:id>', methods=['GET', 'POST'])
|
||||
def update(id):
|
||||
geodata = GeoData.query.get(id)
|
||||
|
||||
if request.method == 'POST':
|
||||
geodata.location = request.form['location']
|
||||
geodata.latitude = float(request.form['latitude'])
|
||||
geodata.longitude = float(request.form['longitude'])
|
||||
|
||||
db.session.commit()
|
||||
return redirect(url_for('index'))
|
||||
|
||||
return render_template('update.html', geodata=geodata)
|
||||
|
||||
@app.route('/delete/<int:id>')
|
||||
def delete(id):
|
||||
geodata = GeoData.query.get(id)
|
||||
db.session.delete(geodata)
|
||||
db.session.commit()
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app.route('/geodata/<int:geodata_id>', methods=['GET'])
|
||||
def get_geodata(geodata_id):
|
||||
geodata = GeoData.query.get(geodata_id)
|
||||
if geodata:
|
||||
return jsonify({
|
||||
'id': geodata.id,
|
||||
'location': geodata.location,
|
||||
'latitude': geodata.latitude,
|
||||
'longitude': geodata.longitude
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': 'Геоданные не найдены'}), 404
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, port=5001)
|
BIN
simonov_nikita_lab_3/geodata_service/instance/geodata.db
Normal file
BIN
simonov_nikita_lab_3/geodata_service/instance/geodata.db
Normal file
Binary file not shown.
5
simonov_nikita_lab_3/geodata_service/requirements.txt
Normal file
5
simonov_nikita_lab_3/geodata_service/requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Flask==3.0.0
|
||||
requests==2.31.0
|
||||
gunicorn==21.2.0
|
||||
SQLAlchemy==2.0.25
|
||||
Flask-SQLAlchemy==3.1.1
|
62
simonov_nikita_lab_3/geodata_service/templates/index.html
Normal file
62
simonov_nikita_lab_3/geodata_service/templates/index.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GeoData CRUD</title>
|
||||
|
||||
<!-- Подключение стилей Bootstrap -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="mt-5 mb-4">Геоданные</h1>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Местоположение</th>
|
||||
<th>Широта</th>
|
||||
<th>Долгота</th>
|
||||
<th>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for data in geodata %}
|
||||
<tr>
|
||||
<td>{{ data.id }}</td>
|
||||
<td>{{ data.location }}</td>
|
||||
<td>{{ data.latitude }}</td>
|
||||
<td>{{ data.longitude }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('update', id=data.id) }}" class="btn btn-warning btn-sm">Изменить</a>
|
||||
<a href="{{ url_for('delete', id=data.id) }}" class="btn btn-danger btn-sm">Удалить</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<form action="{{ url_for('add') }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="location">Местоположение:</label>
|
||||
<input type="text" name="location" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="latitude">Широта:</label>
|
||||
<input type="number" name="latitude" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="longitude">Долгота:</label>
|
||||
<input type="number" name="longitude" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Добавить геоданные</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Подключение скриптов Bootstrap (необходимо для некоторых компонентов) -->
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
36
simonov_nikita_lab_3/geodata_service/templates/update.html
Normal file
36
simonov_nikita_lab_3/geodata_service/templates/update.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Обновление геоданных</title>
|
||||
|
||||
<!-- Подключение стилей Bootstrap -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="mt-5 mb-4">Обновление геоданных</h1>
|
||||
<form action="{{ url_for('update', id=geodata.id) }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="location">Местоположение:</label>
|
||||
<input type="text" name="location" value="{{ geodata.location }}" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="latitude">Широта:</label>
|
||||
<input type="number" name="latitude" value="{{ geodata.latitude }}" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="longitude">Долгота:</label>
|
||||
<input type="number" name="longitude" value="{{ geodata.longitude }}" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Обновить геоданные</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Подключение скриптов Bootstrap (необходимо для некоторых компонентов) -->
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
4
simonov_nikita_lab_3/nginx/Dockerfile
Normal file
4
simonov_nikita_lab_3/nginx/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
||||
FROM nginx
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
27
simonov_nikita_lab_3/nginx/nginx.conf
Normal file
27
simonov_nikita_lab_3/nginx/nginx.conf
Normal file
@ -0,0 +1,27 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
location /geodata-service/ {
|
||||
proxy_pass http://geodata-service:5001/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /user-service/ {
|
||||
proxy_pass http://user-service:5002/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
}
|
137
simonov_nikita_lab_3/readme.md
Normal file
137
simonov_nikita_lab_3/readme.md
Normal file
@ -0,0 +1,137 @@
|
||||
# Лабораторная работа №3.
|
||||
|
||||
## Задание
|
||||
|
||||
- Создать 2 микросервиса, реализующих CRUD на связанных сущностях.
|
||||
- Реализовать механизм синхронного обмена сообщениями между микросервисами.
|
||||
- Реализовать шлюз на основе прозрачного прокси-сервера nginx.
|
||||
|
||||
Вариант: геоданные и пользователи
|
||||
|
||||
## Выбранные сервисы
|
||||
|
||||
Были написаны два сервиса на языке python с технологией flask:
|
||||
|
||||
- Сервис geodata_service, хранящий геоданные и реализующий CRUD операции с ними через HTTP запросы.
|
||||
- Сервис user_service, хранящий данные о пользователях и реализующий CRUD операции с ними через HTTP запросы.
|
||||
|
||||
## Docker-файл для geodata_service
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.11
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . /app
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5001", "geodata_service:app"]
|
||||
```
|
||||
|
||||
## Docker-файл для user_service
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.11
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . /app
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5002", "user_service:app"]
|
||||
```
|
||||
|
||||
## Docker-файл для nginx
|
||||
|
||||
```dockerfile
|
||||
FROM nginx
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
## nginx.conf
|
||||
|
||||
```nginx
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
location /geodata-service/ {
|
||||
proxy_pass http://geodata-service:5001/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /user-service/ {
|
||||
proxy_pass http://user-service:5002/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Docker-compose
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
geodata-service:
|
||||
build:
|
||||
context: ./geodata_service
|
||||
ports:
|
||||
- "5001:5001"
|
||||
networks:
|
||||
- my_network
|
||||
restart: always
|
||||
|
||||
user-service:
|
||||
build:
|
||||
context: ./user_service
|
||||
ports:
|
||||
- "5002:5002"
|
||||
networks:
|
||||
- my_network
|
||||
restart: always
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- geodata-service
|
||||
- user-service
|
||||
networks:
|
||||
- my_network
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
my_network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Запуск
|
||||
|
||||
Командой в консоли проекта:
|
||||
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
|
||||
## Ссылка на видео
|
||||
|
||||
https://drive.google.com/file/d/1dXwl8p4sL60CcTIrtSztYgMNt0RL4qXe/view?usp=sharing
|
||||
|
||||
|
||||
|
6
simonov_nikita_lab_3/user_service/Dockerfile
Normal file
6
simonov_nikita_lab_3/user_service/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
FROM python:3.11
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . /app
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5002", "user_service:app"]
|
BIN
simonov_nikita_lab_3/user_service/instance/users.db
Normal file
BIN
simonov_nikita_lab_3/user_service/instance/users.db
Normal file
Binary file not shown.
5
simonov_nikita_lab_3/user_service/requirements.txt
Normal file
5
simonov_nikita_lab_3/user_service/requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Flask==3.0.0
|
||||
requests==2.31.0
|
||||
gunicorn==21.2.0
|
||||
SQLAlchemy==2.0.25
|
||||
Flask-SQLAlchemy==3.1.1
|
66
simonov_nikita_lab_3/user_service/templates/index.html
Normal file
66
simonov_nikita_lab_3/user_service/templates/index.html
Normal file
@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Пользователи</title>
|
||||
|
||||
<!-- Подключение стилей Bootstrap -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="mt-5 mb-4">Пользователи</h1>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Имя пользователя</th>
|
||||
<th>Email</th>
|
||||
<th>Местоположение</th>
|
||||
<th>Широта</th>
|
||||
<th>Долгота</th>
|
||||
<th>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.id }}</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>{{ user.location }}</td>
|
||||
<td>{{ user.latitude }}</td>
|
||||
<td>{{ user.longitude }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('update', id=user.id) }}" class="btn btn-warning btn-sm">Изменить</a>
|
||||
<a href="{{ url_for('delete', id=user.id) }}" class="btn btn-danger btn-sm">Удалить</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<form action="{{ url_for('add') }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="username">Имя пользователя:</label>
|
||||
<input type="text" name="username" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" name="email" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="geodata">ID геоданных:</label>
|
||||
<input type="text" name="geodata" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Добавить пользователя</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Подключение скриптов Bootstrap (необходимо для некоторых компонентов) -->
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
36
simonov_nikita_lab_3/user_service/templates/update.html
Normal file
36
simonov_nikita_lab_3/user_service/templates/update.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Обновление пользователя</title>
|
||||
|
||||
<!-- Подключение стилей Bootstrap -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="mt-5 mb-4">Обновление пользователя</h1>
|
||||
<form action="{{ url_for('update', id=user.id) }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="username">Имя пользователя:</label>
|
||||
<input type="text" name="username" value="{{ user.username }}" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" name="email" value="{{ user.email }}" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="geodata">ID геоданных:</label>
|
||||
<input type="text" name="geodata" value="{{ user.geodata }}" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Обновить пользователя</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Подключение скриптов Bootstrap (необходимо для некоторых компонентов) -->
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
77
simonov_nikita_lab_3/user_service/user_service.py
Normal file
77
simonov_nikita_lab_3/user_service/user_service.py
Normal file
@ -0,0 +1,77 @@
|
||||
from flask import Flask, render_template, request, redirect, url_for
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
import requests
|
||||
|
||||
app_users = Flask(__name__)
|
||||
app_users.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
|
||||
db_users = SQLAlchemy(app_users)
|
||||
|
||||
class User(db_users.Model):
|
||||
id = db_users.Column(db_users.Integer, primary_key=True)
|
||||
username = db_users.Column(db_users.String(50), nullable=False)
|
||||
email = db_users.Column(db_users.String(50), nullable=False)
|
||||
geodata = db_users.Column(db_users.Integer, nullable=True)
|
||||
|
||||
# Убедимся, что создание таблицы происходит внутри контекста приложения
|
||||
with app_users.app_context():
|
||||
db_users.create_all()
|
||||
|
||||
# Функция для получения геоданных по ID
|
||||
def get_geodata(geodata_id):
|
||||
geodata_service_url = f'http://localhost:5001/geodata/{geodata_id}' # Замените на ваш реальный URL
|
||||
response = requests.get(geodata_service_url)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
return {'error': 'Геоданные не найдены'}
|
||||
|
||||
@app_users.route('/')
|
||||
def index():
|
||||
users_data = User.query.all()
|
||||
|
||||
# Обновляем информацию о пользователе с геоданными
|
||||
for user in users_data:
|
||||
geodata_id = user.geodata
|
||||
user_geodata = get_geodata(geodata_id)
|
||||
user.location = user_geodata.get('location', 'N/A')
|
||||
user.latitude = user_geodata.get('latitude', 'N/A')
|
||||
user.longitude = user_geodata.get('longitude', 'N/A')
|
||||
|
||||
return render_template('index.html', users=users_data)
|
||||
|
||||
@app_users.route('/add', methods=['POST'])
|
||||
def add():
|
||||
username = request.form['username']
|
||||
email = request.form['email']
|
||||
geodata = request.form['geodata']
|
||||
|
||||
new_user = User(username=username, email=email, geodata=geodata)
|
||||
db_users.session.add(new_user)
|
||||
db_users.session.commit()
|
||||
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app_users.route('/update/<int:id>', methods=['GET', 'POST'])
|
||||
def update(id):
|
||||
user = User.query.get(id)
|
||||
|
||||
if request.method == 'POST':
|
||||
user.username = request.form['username']
|
||||
user.email = request.form['email']
|
||||
user.geodata = request.form['geodata']
|
||||
|
||||
db_users.session.commit()
|
||||
return redirect(url_for('index'))
|
||||
|
||||
return render_template('update.html', user=user)
|
||||
|
||||
@app_users.route('/delete/<int:id>')
|
||||
def delete(id):
|
||||
user = User.query.get(id)
|
||||
db_users.session.delete(user)
|
||||
db_users.session.commit()
|
||||
return redirect(url_for('index'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app_users.run(debug=True, port=5002)
|
Loading…
Reference in New Issue
Block a user