forked from orson/bachemap
auth semi-working, utility templates semi-working
This commit is contained in:
parent
e5ab135696
commit
21d39f24d5
156
app.py
156
app.py
@ -1,21 +1,45 @@
|
|||||||
from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory
|
from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory
|
||||||
from flask_pymongo import PyMongo
|
from flask_pymongo import PyMongo, ObjectId
|
||||||
|
from flask_login import LoginManager, UserMixin, login_user, login_required, current_user, logout_user
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from flask_pymongo import ObjectId
|
||||||
import os
|
import os
|
||||||
|
from uuid import uuid4
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import StringField, FileField, SubmitField, DateTimeField, SelectField, PasswordField
|
||||||
|
from wtforms.validators import DataRequired, Length
|
||||||
|
|
||||||
|
|
||||||
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config["MONGO_URI"] = "mongodb://localhost:27017/mapPinsDB"
|
app.config["MONGO_URI"] = "mongodb://localhost:27017/mapDB"
|
||||||
app.config['UPLOAD_FOLDER'] = 'uploads'
|
app.config['UPLOAD_FOLDER'] = 'uploads'
|
||||||
app.config['SECRET_KEY'] = 'supersecretkey'
|
app.config['SECRET_KEY'] = 'supersecretkey'
|
||||||
app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'}
|
app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'}
|
||||||
|
|
||||||
mongo = PyMongo(app)
|
mongo = PyMongo(app)
|
||||||
|
login_manager = LoginManager(app)
|
||||||
|
login_manager.session_protection = "strong"
|
||||||
#form = PinForm()
|
#form = PinForm()
|
||||||
|
|
||||||
from flask_wtf import FlaskForm
|
class User(UserMixin):
|
||||||
from wtforms import StringField, FileField, SubmitField, DateTimeField, SelectField
|
def __init__(self, user_data):
|
||||||
from wtforms.validators import DataRequired
|
self.id = str(user_data['_id'])
|
||||||
|
self.username = user_data['username']
|
||||||
|
self.referral_code = user_data['referral_code']
|
||||||
|
self.invited_by = user_data.get('invited_by')
|
||||||
|
self.is_admin = user_data.get('is_admin', False)
|
||||||
|
self.pwd = user_data.get('pwd')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(user_id):
|
||||||
|
user_data = mongo.db.users.find_one({"_id": ObjectId(user_id)})
|
||||||
|
if user_data:
|
||||||
|
return User(user_data)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
class PinForm(FlaskForm):
|
class PinForm(FlaskForm):
|
||||||
description = StringField('Description', validators=[DataRequired()])
|
description = StringField('Description', validators=[DataRequired()])
|
||||||
@ -24,6 +48,22 @@ class PinForm(FlaskForm):
|
|||||||
typeofpin = SelectField('Tipo de cosa', choices=['bache', 'coladera', 'obra sin terminar', 'escombro', 'robo-asalto'])
|
typeofpin = SelectField('Tipo de cosa', choices=['bache', 'coladera', 'obra sin terminar', 'escombro', 'robo-asalto'])
|
||||||
submit = SubmitField('Agregar')
|
submit = SubmitField('Agregar')
|
||||||
|
|
||||||
|
class LoginForm(FlaskForm):
|
||||||
|
username = StringField('Usuario', validators=[DataRequired()])
|
||||||
|
pwd = PasswordField('Tu clave', validators=[DataRequired()])
|
||||||
|
submit = SubmitField('Entrar')
|
||||||
|
|
||||||
|
def Unique(model, field, message=None):
|
||||||
|
def _unique(form, field_data):
|
||||||
|
if mongo.db[model.__name__.lower()].find_one({field.name: field_data.data}):
|
||||||
|
raise ValidationError(message or f"{field.name} must be unique.")
|
||||||
|
return _unique
|
||||||
|
|
||||||
|
class RegistrationForm(FlaskForm):
|
||||||
|
username = StringField('Nombre de usuarix', validators=[DataRequired(), Unique('users', StringField('username', message="Username already exists"))])
|
||||||
|
pwd = PasswordField('Clave', validators=[DataRequired(), Length(min=10), Unique('users', StringField('pwd', message="Username already exists"))])
|
||||||
|
referral = StringField('ID de quien te invito', [DataRequired()])
|
||||||
|
submit = SubmitField('Registrar')
|
||||||
|
|
||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
|
return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
|
||||||
@ -57,6 +97,7 @@ def index():
|
|||||||
'lat': request.form['lat'],
|
'lat': request.form['lat'],
|
||||||
'lng': request.form['lng'],
|
'lng': request.form['lng'],
|
||||||
'typeofpin': request.form['typeofpin'],
|
'typeofpin': request.form['typeofpin'],
|
||||||
|
'added_by': current_user.id,
|
||||||
}
|
}
|
||||||
mongo.db.pins.insert_one(pin)
|
mongo.db.pins.insert_one(pin)
|
||||||
flash('¡Gracias por tu aportación!')
|
flash('¡Gracias por tu aportación!')
|
||||||
@ -74,5 +115,110 @@ def index():
|
|||||||
def download_file(name):
|
def download_file(name):
|
||||||
return send_from_directory(app.config["UPLOAD_FOLDER"], name)
|
return send_from_directory(app.config["UPLOAD_FOLDER"], name)
|
||||||
|
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(user_id):
|
||||||
|
return User.get(user_id)
|
||||||
|
|
||||||
|
@app.route('/registrame/<referral_code>', methods=['GET', 'POST'])
|
||||||
|
def registrame(referral_code):
|
||||||
|
inviter = mongo.db.users.find_one({"referral_code": referral_code})
|
||||||
|
if not inviter:
|
||||||
|
return "Ooops, parece que nadie te invitó aquí", 404
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.form['username']
|
||||||
|
pwd = request.form['pwd']
|
||||||
|
new_user_data = {
|
||||||
|
"username": username,
|
||||||
|
"pwd": generate_password_hash(pwd),
|
||||||
|
"referral_code": str(uuid4()),
|
||||||
|
"invited_by": str(inviter['_id']),
|
||||||
|
"is_admin": False
|
||||||
|
}
|
||||||
|
new_user_id = mongo.db.users.insert_one(new_user_data).inserted_id
|
||||||
|
invite_link = url_for('registrame', referral_code=new_user_data['referral_code'], _external=True)
|
||||||
|
return render_template('dashboard.html', invite_link=invite_link)
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
return render_template('register.html', form=RegistrationForm())
|
||||||
|
|
||||||
|
@app.route('/thelogin', methods=['GET', 'POST'])
|
||||||
|
def thelogin():
|
||||||
|
form2 = LoginForm()
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.form['username']
|
||||||
|
pwd = request.form['pwd']
|
||||||
|
user_data = mongo.db.users.find_one({"username": username})
|
||||||
|
if user_data and check_password_hash(user_data['pwd'], pwd):
|
||||||
|
user = User(user_data)
|
||||||
|
login_user(user)
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
else:
|
||||||
|
return render_template('login.html', messages = 'Ooops, no hay tal usuario')
|
||||||
|
return render_template('login.html',form=form2)
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
@login_required
|
||||||
|
def logout():
|
||||||
|
logout_user()
|
||||||
|
flash('You have successfully logged yourself out.')
|
||||||
|
return redirect('/')
|
||||||
|
|
||||||
|
@app.route('/desheredame/<user_id>')
|
||||||
|
@login_required
|
||||||
|
def desheredame(user_id):
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
else:
|
||||||
|
user_to_remove = mongo.db.users.find_one({"invited_by": user_id})
|
||||||
|
if not user_to_remove:
|
||||||
|
return "A este ya me lo desheredaron", 404
|
||||||
|
else:
|
||||||
|
mongo.db.users.delete_many({"invited_by": user_id})
|
||||||
|
mongo.db.users.delete_one({"_id": ObjectId(user_id)})
|
||||||
|
mongo.db.pins.delete_many({"user_id": user_id})
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
|
@app.route("/remove_pin/<pin_id>")
|
||||||
|
@login_required
|
||||||
|
def remove_pin(pin_id):
|
||||||
|
actual_pin = mongo.db.pins.find_one({"_id": pin_id})
|
||||||
|
added_by = actual_pin.added_by
|
||||||
|
if not current_user.is_admin or current_user.id != added_by:
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
else:
|
||||||
|
mongo.db.pins.delete_one({"_id": ObjectId(pin_id)})
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
|
@app.route('/dashboard')
|
||||||
|
@login_required
|
||||||
|
def dashboard():
|
||||||
|
if not current_user.is_authenticated:
|
||||||
|
return redirect(url_for('thelogin'))
|
||||||
|
if not current_user.is_admin:
|
||||||
|
pins = list(mongo.db.pins.find({"added_by": current_user.id}))
|
||||||
|
return render_template('dashboard.html', pins=pins)
|
||||||
|
if current_user.is_admin:
|
||||||
|
users = list(mongo.db.users.find())
|
||||||
|
pins = list(mongo.db.pins.find())
|
||||||
|
return render_template('dashboard.html', users=users, pins=pins)
|
||||||
|
|
||||||
|
@app.cli.command('add_user')
|
||||||
|
def add_user():
|
||||||
|
username = input("Enter Username:\n")
|
||||||
|
pwd = input("Add pass:\n")
|
||||||
|
|
||||||
|
admin_user = {
|
||||||
|
"username": username,
|
||||||
|
"pwd": generate_password_hash(pwd),
|
||||||
|
"referral_code": str(uuid4()),
|
||||||
|
"invited_by": None,
|
||||||
|
"is_admin": True
|
||||||
|
}
|
||||||
|
mongo.db.users.insert_one(admin_user)
|
||||||
|
print(f"Admin {username} added! Referral code is {admin_user['referral_code']}")
|
||||||
|
return app
|
||||||
|
|
||||||
|
app=create_app()
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
||||||
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
||||||
crossorigin=""></script>
|
crossorigin=""></script>
|
||||||
|
<script type="text/javascript" src="https://stamen-maps.a.ssl.fastly.net/js/tile.stamen.js?v1.3.0"></script>
|
||||||
|
|
||||||
|
|
||||||
<!--<link rel="stylesheet" href="{{ url_for('static', filename='leaflet.css') }}">
|
<!--<link rel="stylesheet" href="{{ url_for('static', filename='leaflet.css') }}">
|
||||||
@ -45,7 +46,13 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<div id="pinner-modal" style="z-index:999;position:absolute;top:7vh" hidden="true">
|
<div id="pinner-modal" style="z-index:999;position:absolute;top:7vh" hidden="true">
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
{% include 'add_pin.html' %}
|
{% include 'add_pin.html' %}
|
||||||
|
{% else %}
|
||||||
|
<div >
|
||||||
|
<h3>Seguramente quieres hacer <a href="{{ url_for('thelogin') }}">login</a></h3>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
16
templates/dashboard.html
Normal file
16
templates/dashboard.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'secondbase.html' %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h3>Hola {{current_user.username}}</h3>
|
||||||
|
<p>Tu link de invitación es:</p>
|
||||||
|
<p>https://baches.qro.mx/registrame/{{current_user.referral_code}}</p>
|
||||||
|
|
||||||
|
{% if pins %}
|
||||||
|
{% for pin in pins %}
|
||||||
|
<p>
|
||||||
|
{{pin}}
|
||||||
|
</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -1,19 +0,0 @@
|
|||||||
<form method="POST" action="/">
|
|
||||||
|
|
||||||
<input type="submit" value="Go">
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form method="POST" enctype="multipart/form-data">
|
|
||||||
{{ form.hidden_tag() }}
|
|
||||||
<div class="form-group">
|
|
||||||
{{form.author.label}} {{form.author(class="form-control")}}
|
|
||||||
{{form.img.label}} {{form.img()}}
|
|
||||||
{{form.latitude()}}
|
|
||||||
{{form.longitude()}}
|
|
||||||
{{form.message.label}}{{form.message(class="form-control")}}
|
|
||||||
<button type="button" name="whereami" id="whereami">Ubicación actual</button>
|
|
||||||
{{form.submit(class="submit-btn")}}
|
|
||||||
</div>
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
{{ form.name.label }} {{ form.name(size=20) }}
|
|
||||||
</form>
|
|
||||||
@ -7,9 +7,8 @@
|
|||||||
var map = new L.map('map', center=([20.57, -100.38], zoom=13));
|
var map = new L.map('map', center=([20.57, -100.38], zoom=13));
|
||||||
var user_marker = new L.marker([20.57, -100.38]);
|
var user_marker = new L.marker([20.57, -100.38]);
|
||||||
var user_radial = new L.circle(L.circle(user_marker.latlng))
|
var user_radial = new L.circle(L.circle(user_marker.latlng))
|
||||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
//L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
attribution: '© OpenStreetMap contributors'
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
{% for pin in pins %}
|
{% for pin in pins %}
|
||||||
var marker = L.marker([{{ pin.lat }}, {{ pin.lng }}]).addTo(map)
|
var marker = L.marker([{{ pin.lat }}, {{ pin.lng }}]).addTo(map)
|
||||||
|
|||||||
12
templates/login.html
Normal file
12
templates/login.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% extends 'secondbase.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<form method="post" enctype="multipart/form-data" style="background-color: rgb(205, 243, 148);">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ form.username.label }}<br>
|
||||||
|
{{ form.username() }}
|
||||||
|
{{ form.pwd.label }}
|
||||||
|
{{ form.pwd() }}
|
||||||
|
|
||||||
|
<p>{{ form.submit() }}</p>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
15
templates/register.html
Normal file
15
templates/register.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'secondbase.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form method="post" enctype="multipart/form-data" style="background-color: rgb(205, 243, 148);">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ form.username.label }}<br>
|
||||||
|
{{ form.username() }}
|
||||||
|
{{ form.pwd.label }}
|
||||||
|
{{ form.pwd() }}
|
||||||
|
|
||||||
|
<p>{{ form.submit() }}</p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
49
templates/secondbase.html
Normal file
49
templates/secondbase.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-theme="light" lang="en" style="background-color: rgb(205, 243, 148); color: black;">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Interactive Map</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='pico.amber.css') }}">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--<link rel="stylesheet" href="{{ url_for('static', filename='leaflet.css') }}">
|
||||||
|
<script src="{{ url_for('static', filename='leaflet.js') }}"></script>-->
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body style="background-color: rgb(205, 243, 148); color: black;">
|
||||||
|
<nav style="z-index: 5; height: 7vh;">
|
||||||
|
<ul>
|
||||||
|
<li><h2>El Bachemapa</h2>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><button id="pinner-top">Agregar</button></li>
|
||||||
|
<li><a href="/quienes">Quienes somos</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
<ul class="flashes">
|
||||||
|
{% for message in messages %}
|
||||||
|
<li>{{message}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
<main class="" style="padding:0px;height: 100vh; width:100vw; z-index: 5; position: absolute;">
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user