Added comments/reports under SAR jobs

GPX functionality still WIP
This commit is contained in:
Vadim Likholetov 2023-11-14 12:07:43 +02:00
parent e124209da0
commit cd6c2c216d
6 changed files with 174 additions and 100 deletions

View File

@ -11,6 +11,8 @@ class User(UserMixin, db.Model):
password = db.Column(db.String(50)) password = db.Column(db.String(50))
role_id = db.Column(db.Integer, db.ForeignKey('role.id')) role_id = db.Column(db.Integer, db.ForeignKey('role.id'))
role = db.relationship('Role', backref=db.backref('users', lazy='dynamic')) role = db.relationship('Role', backref=db.backref('users', lazy='dynamic'))
def __repr__(self):
return self.username
class Role(db.Model): class Role(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -32,8 +34,7 @@ class SARCall(db.Model):
description = db.Column(db.Text, nullable=True) description = db.Column(db.Text, nullable=True)
description_hidden = db.Column(db.Text, nullable=True) description_hidden = db.Column(db.Text, nullable=True)
search_manager_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) search_manager_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
gpx_data = db.Column(db.Text, nullable=True) # This will store GPX data as a text search_manager = db.relationship('User', backref=db.backref('sar_calls', lazy=True))
class SARCategory(db.Model): class SARCategory(db.Model):
id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False) id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
@ -63,7 +64,7 @@ class GPSTrack(db.Model):
class Comment(db.Model): class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.Text, nullable=True) text = db.Column(db.Text, nullable=True)
gpx_data = db.Column(db.Text, nullable=True) gpx_data = db.Column(db.Text (length=4294967295) , nullable=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
user = db.relationship('User', backref=db.backref('comments', lazy=True)) user = db.relationship('User', backref=db.backref('comments', lazy=True))
sar_call_id = db.Column(db.Integer, db.ForeignKey('sar_call.id'), nullable=False) sar_call_id = db.Column(db.Integer, db.ForeignKey('sar_call.id'), nullable=False)

View File

@ -1,8 +1,8 @@
from app import app, db from app import app, db
from flask import request, redirect, flash, render_template, url_for from flask import request, redirect, flash, render_template, url_for, jsonify
from flask_login import login_required, current_user from flask_login import login_required, current_user
from dateutil import parser from dateutil import parser
from models import SARCall, GPSTrack, SARCategory, SARStatus, User from models import SARCall, Comment, GPSTrack, SARCategory, SARStatus, User
@app.route('/create_sar', methods=['GET', 'POST']) @app.route('/create_sar', methods=['GET', 'POST'])
@ -114,30 +114,29 @@ def add_comment(sar_call_id):
comment = Comment(text=text, gpx_data=gpx_data, user_id=current_user.id, sar_call_id=sar_call_id) comment = Comment(text=text, gpx_data=gpx_data, user_id=current_user.id, sar_call_id=sar_call_id)
db.session.add(comment) db.session.add(comment)
db.session.commit() db.session.commit()
return redirect(url_for('view_sar', sar_call_id=sar_call_id)) return redirect(url_for('sar_details', id=sar_call_id))
@app.route('/edit_comment/<int:comment_id>', methods=['GET', 'POST'])
@app.route('/edit_comment/<int:comment_id>', methods=['POST'])
@login_required @login_required
def edit_comment(comment_id): def edit_comment(comment_id):
comment = Comment.query.get_or_404(comment_id) comment = Comment.query.get_or_404(comment_id)
if current_user.id != comment.user_id and current_user.id != 1 and current_user.id != comment.sar_call.user_id: # Permission checks...
abort(403)
# Handle the form submission and save changes comment_text = request.form.get('comment')
if request.method == 'POST': comment.text = comment_text
comment.text = request.form.get('text')
gpx_file = request.files.get('gpx_file')
if gpx_file:
comment.gpx_data = gpx_file.read().decode("utf-8")
db.session.commit() db.session.commit()
return redirect(url_for('view_sar', sar_call_id=comment.sar_call_id))
# return jsonify(success=True) # or return relevant response
return redirect(url_for('sar_details', id=comment.sar_call_id))
@app.route('/delete_comment/<int:comment_id>', methods=['POST']) @app.route('/delete_comment/<int:id>', methods=['GET', 'POST'])
@login_required @login_required
def delete_comment(comment_id): def delete_comment(id):
comment = Comment.query.get_or_404(comment_id) comment = Comment.query.get_or_404(id)
if current_user.id != comment.user_id and current_user.id != 1 and current_user.id != comment.sar_call.user_id: # if current_user.id != comment.user_id and current_user.id != 1 and current_user.id != comment.sar_call.user_id:
abort(403) # abort(403)
db.session.delete(comment) db.session.delete(comment)
db.session.commit() db.session.commit()
return redirect(url_for('view_sar', sar_call_id=comment.sar_call_id)) flash('Comment deleted successfully!', 'success')
return redirect(url_for('sar_details', id=comment.sar_call_id))

View File

@ -124,7 +124,7 @@
{# });#} {# });#}
{# map.addLayer(gpxLayer);#} {# map.addLayer(gpxLayer);#}
{#}) {#})
;
#} #}
// If editing, set the marker to the existing coordinates // If editing, set the marker to the existing coordinates

View File

@ -33,7 +33,8 @@
<div> <div>
<button type="button" id="today_button" class="btn btn-secondary">Today</button> <button type="button" id="today_button" class="btn btn-secondary">Today</button>
</div> </div>
<input type="date" name="finish_date" id="finish_date" class="form-control" value="{{ sar_call.finish_date }}" > <input type="date" name="finish_date" id="finish_date" class="form-control"
value="{{ sar_call.finish_date }}">
</div> </div>
<div class="form-group"> <div class="form-group">
@ -69,11 +70,11 @@
<textarea name="description_hidden" class="form-control">{{ sar_call.description_hidden }}</textarea> <textarea name="description_hidden" class="form-control">{{ sar_call.description_hidden }}</textarea>
</div> </div>
{# <!-- GPX Track Fields (You can expand upon this based on the previous discussion about multiple tracks) -->#} {# <!-- GPX Track Fields (You can expand upon this based on the previous discussion about multiple tracks) -->#}
{# <div class="form-group">#} {# <div class="form-group">#}
{# <label for="gpx_file">Upload GPX Track:</label>#} {# <label for="gpx_file">Upload GPX Track:</label>#}
{# <input type="file" name="gpx_file">#} {# <input type="file" name="gpx_file">#}
{# </div>#} {# </div>#}
<button type="submit" class="btn btn-primary">Update</button> <button type="submit" class="btn btn-primary">Update</button>
</form> </form>
@ -104,7 +105,7 @@
} }
</script> </script>
<script> <script>
document.getElementById('today_button').addEventListener('click', function() { document.getElementById('today_button').addEventListener('click', function () {
var today = new Date(); var today = new Date();
var dd = String(today.getDate()).padStart(2, '0'); var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0! var mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0!
@ -112,7 +113,7 @@
today = yyyy + '-' + mm + '-' + dd; today = yyyy + '-' + mm + '-' + dd;
document.getElementById('finish_date').value = today; document.getElementById('finish_date').value = today;
}); });
</script> </script>
</div> </div>

View File

@ -6,14 +6,20 @@
{% block content %} {% block content %}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" /> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<style> <style>
#map { height: 400px; } #map {
.button { margin: 5px; } height: 400px;
}
.button {
margin: 5px;
}
</style> </style>
<div class="container mt-4"> <div class="container mt-4">
<h1 class="mb-4">SAR Job Details</h1> <h1 class="mb-4">SAR Job Details</h1>
<div class="card mb-4"> <div class="card mb-4">
<div class="card-body"> <div class="card-body">
@ -24,32 +30,66 @@
</div> </div>
</div> </div>
<div id="map" class="mb-4"></div>
<div> <div>
<a href="{{ url_for('edit_sar', id=sar.id) }}" class="btn btn-primary">Edit</a> <a href="{{ url_for('edit_sar', id=sar.id) }}" class="btn btn-primary">Edit</a>
<a href="{{ url_for('delete_sar', id=sar.id) }}" class="btn btn-danger">Delete</a> <a href="{{ url_for('delete_sar', id=sar.id) }}" class="btn btn-danger">Delete</a>
</div> </div>
</div>
<div id="map" class="mb-4"></div>
<!-- Display Comments --> <!-- Display Comments -->
{% for comment in sar_call.comments %} {% for comment in sar.comments %}
<div class="comment"> <div class="comment">
<strong>{{ comment.user.username }}</strong>: <strong>{{ comment.user.username }}</strong>:
<p>{{ comment.text }}</p> <p id="comment-text-{{ comment.id }}">{{ comment.text }}</p>
{% if comment.gpx_data %} {% if comment.gpx_data %}
<!-- Display the GPX data on the map --> <!-- Display the GPX data on the map -->
{% endif %} {% endif %}
{% if current_user.id == comment.user_id or current_user.id == 1 or current_user.id == sar_call.user_id %} {% if current_user.id == comment.user_id or current_user.id == 1 or current_user.id == sar.user_id %}
<a href="{{ url_for('edit_comment', comment_id=comment.id) }}">Edit</a> <button class="edit-comment-btn" data-comment-id="{{ comment.id }}"
<a href="{{ url_for('delete_comment', comment_id=comment.id) }}">Delete</a> data-comment-text="{{ comment.text }}">Edit
</button>
<button class="delete-comment-btn">
<a href="{{ url_for('delete_comment', id=comment.id) }}">Delete</a>
</button>
{% endif %} {% endif %}
</div> </div>
{% endfor %} {% endfor %}
<!-- Add Comment Form --> <!-- Edit Comment Modal -->
<form action="{{ url_for('add_comment', sar_call_id=sar_call.id) }}" method="post" enctype="multipart/form-data"> <div class="modal fade" id="editCommentModal" tabindex="-1" aria-labelledby="editCommentModalLabel"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editCommentModalLabel">Edit Comment</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editCommentForm">
<div class="form-group">
<label for="commentText" class="col-form-label">Comment:</label>
<textarea class="form-control" id="commentText"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="saveComment">Save changes</button>
</div>
</div>
</div>
</div>
<!-- Add Comment Form -->
<form action="{{ url_for('add_comment', sar_call_id=sar.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>
@ -59,12 +99,9 @@
<input type="file" name="gpx_file"> <input type="file" name="gpx_file">
</div> </div>
<button type="submit" class="btn btn-primary">Add Comment</button> <button type="submit" class="btn btn-primary">Add Comment</button>
</form> </form>
</div>
<script> <script>
var map = L.map('map').setView([{{ sar.latitude }}, {{ sar.longitude }}], 13); var map = L.map('map').setView([{{ sar.latitude }}, {{ sar.longitude }}], 13);
@ -76,4 +113,40 @@
</script> </script>
<script>
var commentId; // Declare this outside of the .edit-comment-btn click handler
var commentText; // Declare this outside of the .edit-comment-btn click handler
$(document).ready(function () {
$('.edit-comment-btn').on('click', function () {
// Get the comment data
commentId = $(this).data('comment-id');
commentText = $(this).data('comment-text');
// Set the comment data in the modal
$('#commentText').val(commentText);
$('#editCommentModal').modal('show');
// Save changes
$('#saveComment').on('click', function () {
$.ajax({
url: '/edit_comment/' + commentId,
method: 'POST',
data: {comment: $('#commentText').val()},
success: function (response) {
// Update the comment display on the page
$('#comment-text-' + commentId).text( $('#commentText').val());
$('#editCommentModal').modal('hide');
// Update the comment display on the page as needed
},
error: function () {
// Handle error
alert("Error updating comment");
}
});
});
});
});
</script>
{% endblock %} {% endblock %}