Added display of records without login

This commit is contained in:
Vadim Likholetov 2023-11-19 23:08:19 +02:00
parent 2143b261ac
commit 81858e309d
9 changed files with 107 additions and 47 deletions

12
.idea/dataSources.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="mysql@localhost" uuid="5dc17320-52b3-48ce-b415-835ec0d6e7b6">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3306/sarbaseapp</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{leaflet-control-geocoder}" />
</component>
</project>

View File

@ -23,10 +23,10 @@ class UserModelView(AdminModelView):
admin = Admin(app, name='SAR Admin', template_mode='bootstrap3') admin = Admin(app, name='SAR Admin', template_mode='bootstrap3')
admin.add_view(UserModelView(User, db.session)) admin.add_view(UserModelView(User, db.session))
admin.add_view(AdminModelView(Role, db.session))
admin.add_view(AdminModelView(SARCall, db.session)) admin.add_view(AdminModelView(SARCall, db.session))
admin.add_view(AdminModelView(Comment, db.session)) admin.add_view(AdminModelView(Comment, db.session))
admin.add_view(AdminModelView(GPSTrack, db.session)) admin.add_view(AdminModelView(GPSTrack, db.session))
admin.add_view(AdminModelView(Role, db.session, category="Dictionaries"))
admin.add_view(AdminModelView(SARCategory, db.session, category="Dictionaries")) admin.add_view(AdminModelView(SARCategory, db.session, category="Dictionaries"))
admin.add_view(AdminModelView(SARStatus, db.session, category="Dictionaries")) admin.add_view(AdminModelView(SARStatus, db.session, category="Dictionaries"))
admin.add_view(AdminModelView(SARResult, db.session, category="Dictionaries")) admin.add_view(AdminModelView(SARResult, db.session, category="Dictionaries"))

2
app.py
View File

@ -47,7 +47,7 @@ import dashboard
@app.route('/') @app.route('/')
def hello_world(): # put application's code here def hello_world(): # put application's code here
return redirect(url_for('dashboard')) return redirect(url_for('list_sar'))
@app.route('/set_language/<lang_code>') @app.route('/set_language/<lang_code>')

View File

@ -30,6 +30,7 @@ class SARCall(db.Model):
def __repr__(self): def __repr__(self):
return self.title return self.title
class User(UserMixin, db.Model): class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
created = db.Column(db.DateTime, nullable=False, default=datetime.now) created = db.Column(db.DateTime, nullable=False, default=datetime.now)

View File

@ -1,10 +1,11 @@
from dateutil import parser from dateutil import parser
from flask import request, redirect, flash, render_template, url_for, jsonify, Response from flask import request, redirect, flash, render_template, url_for, jsonify, Response
from flask_login import login_required, current_user from flask_login import login_required, current_user
from sqlalchemy import or_ from sqlalchemy import or_, and_
from sqlalchemy.orm import aliased
from app import app, db from app import app, db
from models import SARCall, Comment, GPSTrack, SARCategory, SARStatus, User, Role from models import SARCall, Comment, GPSTrack, SARCategory, SARStatus, User, Role, SARResult
@app.route('/create_sar', methods=['GET', 'POST']) @app.route('/create_sar', methods=['GET', 'POST'])
@ -14,7 +15,6 @@ def create_sar():
statuses = SARStatus.query.order_by('id').all() statuses = SARStatus.query.order_by('id').all()
managers = User.query.join(Role).filter(or_(Role.name == 'search manager', Role.name == 'admin')).all() managers = User.query.join(Role).filter(or_(Role.name == 'search manager', Role.name == 'admin')).all()
if request.method == 'POST': if request.method == 'POST':
start_date = parser.parse(request.form.get('start_date')) start_date = parser.parse(request.form.get('start_date'))
category = request.form.get('category') category = request.form.get('category')
@ -50,12 +50,20 @@ def create_sar():
@app.route('/list_sar') @app.route('/list_sar')
@login_required
def list_sar(): def list_sar():
sar_calls = SARCall.query.join(User, SARCall.search_officer_id == User.id).join(SARCategory, is_logged_in = current_user.is_authenticated
SARCall.category == SARCategory.id).add_columns( search_officer = aliased(User)
SARCategory, User, SARCall).all() coordination_officer = aliased(User)
return render_template('list_sar.html', sar_calls=sar_calls)
sar_calls = (SARCall.query
.outerjoin(search_officer, and_ (SARCall.search_officer_id == search_officer.id, SARCall.search_officer_id != None))
.join(coordination_officer, SARCall.coordination_officer_id == coordination_officer.id)
.join(SARCategory, SARCall.category == SARCategory.id)
.join(SARStatus, SARCall.status == SARStatus.id)
.add_columns(SARCategory, SARCall, SARStatus)
.all())
return render_template('list_sar.html', sar_calls=sar_calls, is_logged_in=is_logged_in)
@app.route('/edit_sar/<int:id>', methods=['GET', 'POST']) @app.route('/edit_sar/<int:id>', methods=['GET', 'POST'])
@ -94,12 +102,27 @@ def edit_sar(id):
@app.route('/sar_details/<int:id>') @app.route('/sar_details/<int:id>')
def sar_details(id): def sar_details(id):
sar = SARCall.query.get_or_404(id) # Fetch the SARCall record or return 404 is_logged_in = current_user.is_authenticated
search_officer = aliased(User)
coordination_officer = aliased(User)
sar = (SARCall.query
.outerjoin(search_officer,
and_(SARCall.search_officer_id == search_officer.id, SARCall.search_officer_id != None))
.join(coordination_officer, SARCall.coordination_officer_id == coordination_officer.id)
.join(SARCategory, SARCall.category == SARCategory.id)
.join(SARStatus, SARCall.status == SARStatus.id)
.outerjoin(SARResult, and_(SARCall.result == SARResult.id, SARCall.result != None))
.add_columns(SARCall, SARCategory, SARStatus, SARResult)
.filter(SARCall.id == id).first())
comments = Comment.query.filter_by(sar_call_id=id).all()
gpx_files = [id[0] for id in GPSTrack.query.with_entities(GPSTrack.id).filter_by( gpx_files = [id[0] for id in GPSTrack.query.with_entities(GPSTrack.id).filter_by(
sar_call_id=id).all()] # Fetch all GPX files for this SARCall sar_call_id=id).all()] # Fetch all GPX files for this SARCall
comments_with_gpx = [] comments_with_gpx = []
for comment in sar.comments: for comment in comments:
gpx_tracks = GPSTrack.query.filter_by(comment_id=comment.id).all() gpx_tracks = GPSTrack.query.filter_by(comment_id=comment.id).all()
for track in gpx_tracks: for track in gpx_tracks:
comments_with_gpx.append({ comments_with_gpx.append({
@ -109,7 +132,9 @@ def sar_details(id):
"comment": track.gpx_name "comment": track.gpx_name
}) })
return render_template('sar_details.html', sar=sar, gpx_ids=gpx_files, comments_with_gpx=comments_with_gpx) print(sar)
return render_template('sar_details.html', sar=sar, gpx_ids=gpx_files, comments_with_gpx=comments_with_gpx,is_logged_in=is_logged_in)
@app.route('/delete_sar/<int:id>') @app.route('/delete_sar/<int:id>')
@ -180,7 +205,6 @@ def upload_gpx():
@app.route('/get_gpx/<int:gpx_id>') @app.route('/get_gpx/<int:gpx_id>')
@login_required
def get_gpx(gpx_id): def get_gpx(gpx_id):
gpx_file = GPSTrack.query.get_or_404(gpx_id) gpx_file = GPSTrack.query.get_or_404(gpx_id)
return Response(gpx_file.gpx_data, mimetype='application/gpx+xml') return Response(gpx_file.gpx_data, mimetype='application/gpx+xml')

View File

@ -21,9 +21,11 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/list_sar">{{ _('SAR records') }}</a> <a class="nav-link" href="/list_sar">{{ _('SAR records') }}</a>
</li> </li>
{% if current_user.is_authenticated %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/create_sar">{{ _('New record') }}</a> <a class="nav-link" href="/create_sar">{{ _('New record') }}</a>
</li> </li>
{% endif %}
</ul> </ul>
<!-- Display user info and logout link if user is authenticated --> <!-- Display user info and logout link if user is authenticated -->

View File

@ -18,7 +18,10 @@
<th>Category</th> <th>Category</th>
<th>Created by</th> <th>Created by</th>
<th>Manager</th> <th>Manager</th>
{% if is_logged_in %}
<th>Actions</th> <th>Actions</th>
{% endif %}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -26,25 +29,27 @@
<tr class="clickable-row" data-href="{{ url_for('sar_details', id=sar.SARCall.id) }}"> <tr class="clickable-row" data-href="{{ url_for('sar_details', id=sar.SARCall.id) }}">
<td>{{ sar.SARCall.id }}</td> <td>{{ sar.SARCall.id }}</td>
<td>{{ sar.SARCall.title }}</td> <td>{{ sar.SARCall.title }}</td>
<td>{{ sar.SARCall.status }}</td> <td>{{ sar.SARStatus.name }}</td>
<td>{{ sar.SARCall.start_date }}</td> <td>{{ sar.SARCall.start_date }}</td>
<td>{{ sar.SARCall.finish_date }}</td> <td>{{ sar.SARCall.finish_date }}</td>
<td>{{ sar.SARCategory.name }}</td> <td>{{ sar.SARCategory.name }}</td>
<td>{{ sar.User.full_name }}</td> <td>{{ sar.SARCall.coordination_officer.full_name }}</td>
<td>{{ sar.SARCall.manager }}</td> <td>{{ sar.SARCall.search_officer.full_name }}</td>
{% if is_logged_in %}
<td> <td>
<a href="{{ url_for('edit_sar', id=sar.SARCall.id) }}"> <a href="{{ url_for('edit_sar', id=sar.SARCall.id) }}">
<button type="button" class="btn btn-info">Edit</button> <button type="button" class="btn btn-info">Edit</button>
</a> |
<a href="{{ url_for('delete_sar', id=sar.SARCall.id) }}">
<button type="button" class="btn btn-danger">Delete</button>
</a> </a>
{# <a href="{{ url_for('delete_sar', id=sar.SARCall.id) }}">#}
{# <button type="button" class="btn btn-danger">Delete</button>#}
{# </a>#}
</td> </td>
{% endif %}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<a href="/dashboard">Back to Dashboard</a> {# <a href="/dashboard">Back to Dashboard</a>#}
</div> </div>
<script> <script>

View File

@ -28,7 +28,7 @@
</style> </style>
<div class="container mt-4"> <div class="container mt-4">
<h2 class="mb-4">#{{ sar.id }} : {{ sar.title }}</h2> <h2 class="mb-4">#{{ sar.SARCall.id }} : {{ sar.SARCall.title }}</h2>
<div class="card mb-4"> <div class="card mb-4">
<div class="card-body"> <div class="card-body">
<table> <table>
@ -37,27 +37,32 @@
<div class="card-mb5"> <div class="card-mb5">
<div class="card-body"> <div class="card-body">
<div> <div>
<p>Created at: {{ sar.created }}</p> <p>Created at: {{ sar.SARCall.created }}</p>
<p>Last updated: {{ sar.updated }}</p> <p>Last updated: {{ sar.SARCall.updated }}</p>
</div> </div>
<p>Status: {{ sar.status }}</p> <p><strong>Coordination manager:</strong> {{ sar.SARCall.coordination_officer.full_name }}</p>
<p>Category: {{ sar.category }}</p> <p><strong>Search manager:</strong> {{ sar.SARCall.search_officer.full_name }}</p>
<p><strong>Start Date:</strong> {{ sar.start_date }}</p> <p>Status: {{ sar.SARStatus.name }}</p>
<p><strong>Finish Date:</strong> {{ sar.finish_date }}</p> {% if is_logged_in %}
<p>Result: {{ sar.result }}</p> <p>Category: {{ sar.SARCategory.name }}</p>
<p><strong>Manager:</strong> {{ sar.manager_id }}</p> {% endif %}
<p><strong>Start Date:</strong> {{ sar.SARCall.start_date }}</p>
<p><strong>Finish Date:</strong> {{ sar.SARCall.finish_date }}</p>
<p>Result: {{ sar.SARResult.name }}</p>
</div> </div>
</div> </div>
</td> </td>
<td> <td>
<div class="card-mb5"> <div class="card-mb5">
<div class="card-body"> <div class="card-body">
<p>IPP longitude: {{ sar.longitude }} </p> <p>IPP longitude: {{ sar.SARCall.longitude }} </p>
<p>IPP latitude: {{ sar.latitude }}</p> <p>IPP latitude: {{ sar.SARCall.latitude }}</p>
<p>Longitude found: {{ sar.longitude_found }}</p> <p>Longitude found: {{ sar.SARCall.longitude_found }}</p>
<p>Latitude found: {{ sar.latitude_found }}</p> <p>Latitude found: {{ sar.SARCall.latitude_found }}</p>
<p>Description: {{ sar.description }}</p> <p>Description: {{ sar.SARCall.description }}</p>
<p>Description private: {{ sar.description_hidden }}</p> {% if is_logged_in %}
<p>Description private: {{ sar.SARCall.description_hidden }}</p>
{% endif %}
</div> </div>
</div> </div>
</td> </td>
@ -68,15 +73,17 @@
</div> </div>
<div> <div>
<a href="{{ url_for('edit_sar', id=sar.id) }}" class="btn btn-primary">Edit</a> {% if is_logged_in %}
<a href="{{ url_for('delete_sar', id=sar.id) }}" class="btn btn-danger">Delete</a> <a href="{{ url_for('edit_sar', id=sar.SARCall.id) }}" class="btn btn-primary">Edit</a>
<a href="{{ url_for('delete_sar', id=sar.SARCall.id) }}" class="btn btn-danger">Delete</a>
{% endif %}
</div> </div>
<div id="map" class="mb-4"></div> <div id="map" class="mb-4"></div>
<!-- Display Comments --> <!-- Display Comments -->
{% for comment in sar.comments %} {% for comment in sar.SARCall.comments %}
<div class="comment"> <div class="comment">
<div class="card mb-4"> <div class="card mb-4">
<div class="card-body"> <div class="card-body">
@ -97,7 +104,8 @@
{% endfor %} {% endfor %}
{% if current_user.id == comment.user_id or current_user.id == 1 or current_user.id == sar.user_id %} {% if is_logged_in %}
{% if current_user.id == comment.user_id or current_user.id == 1 or current_user.id == sar.SARCall.user_id %}
<button class="edit-comment-btn" data-comment-id="{{ comment.id }}" <button class="edit-comment-btn" data-comment-id="{{ comment.id }}"
data-comment-text="{{ comment.text }}">Edit data-comment-text="{{ comment.text }}">Edit
</button> </button>
@ -113,6 +121,7 @@
</button> </button>
{% endif %} {% endif %}
{% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -147,7 +156,8 @@
<!-- Add Comment Form --> <!-- Add Comment Form -->
<form action="{{ url_for('add_comment', sar_call_id=sar.id) }}" method="post" enctype="multipart/form-data"> {% if is_logged_in %}
<form action="{{ url_for('add_comment', sar_call_id=sar.SARCall.id) }}" method="post" enctype="multipart/form-data">
<div class="form-group"> <div class="form-group">
<label for="text">Comment:</label> <label for="text">Comment:</label>
<textarea name="text" class="form-control"></textarea> <textarea name="text" class="form-control"></textarea>
@ -158,7 +168,7 @@
</div> </div>
<button type="submit" class="btn btn-primary">Add Comment</button> <button type="submit" class="btn btn-primary">Add Comment</button>
</form> </form>
{% endif %}
</div> </div>
<!-- GPX File Upload Modal --> <!-- GPX File Upload Modal -->
@ -183,7 +193,7 @@
</div> </div>
</div> </div>
<input type="hidden" id="commentIdForGPX" name="commentId"> <input type="hidden" id="commentIdForGPX" name="commentId">
<input type="hidden" id="sarIdForGPX" name="sarId" value="{{ sar.id }}"> <input type="hidden" id="sarIdForGPX" name="sarId" value="{{ sar.SARCall.id }}">
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" class="btn btn-primary">Upload</button> <button type="submit" class="btn btn-primary">Upload</button>
</div> </div>
@ -209,12 +219,12 @@
var gpxData = {{ gpx_ids | tojson }}; var gpxData = {{ gpx_ids | tojson }};
var map = L.map('map').setView([{{ sar.latitude }}, {{ sar.longitude }}], 13); var map = L.map('map').setView([{{ sar.SARCall.latitude }}, {{ sar.SARCall.longitude }}], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19, maxZoom: 19,
attribution: '© OpenStreetMap contributors' attribution: '© OpenStreetMap contributors'
}).addTo(map); }).addTo(map);
L.marker([{{ sar.latitude }}, {{ sar.longitude }}]).addTo(map); L.marker([{{ sar.SARCall.latitude }}, {{ sar.SARCall.longitude }}]).addTo(map);
gpxData.forEach(function (id) { gpxData.forEach(function (id) {
loadAndDisplayGPX(id); loadAndDisplayGPX(id);