Flask Web App link user with sqlite3 list problem - python

I am coding a bullying reports web app in python with flask and a database in sqlite3 with 3 lists usuarios, victimas and testigos. Table usuarios is to list all the users (schools) registered and the table victimas is to show all the reports made by students that involve a SPECIFIC SCHOOL. For example: Show all reports from school "Gonza". So when a school logs in it can see all the reports made but the problem is there i can't link the school name with the victims list.
I think the problem is in the session[user_id] in line 162 and then on line 232 when i try to hechos = db.execute("SELECT * FROM victimas WHERE escuela = :escuela", escuela=session["user_id"]) it causes a bug.
I had two different error messages from the debugger that are stated below:
KeyError: 'user_id' in line 232 hechos = db.execute("SELECT * FROM
victimas WHERE escuela = :escuela", escuela=session["user_id"])
Sometimes this error also appears
NameError: name 'escuela' is not defined in line 241, in
tablatestigos return render_template("tablatestigos.html",
escuela=escuela)
#app.route("/regescuela", methods=["GET", "POST"])
def register():
session.clear()
if request.method == "POST":
if not request.form.get("username"):
return apology("No ha introducido un nombre de usuario!")
elif not request.form.get("password"):
return apology("No ha introducido una contraseña!")
elif request.form.get("password") != request.form.get("confirmation"):
return apology("Las contraseñas no coinciden.")
else:
usumayu = request.form.get("username")
return render_template("regescuela.html")
result = db.execute("INSERT INTO usuarios (username, hash) VALUES(:username, :hash)", username= request.form.get("username").upper(), hash=generate_password_hash(request.form.get("password")))
if not result:
return apology("Este usuario ya existe! Prueba con otro!")
session["user_id"] = result[0]["username"]
flash("Registrado!")
return redirect("/")
#app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# Ensure username was submitted
if not request.form.get("username"):
return apology("Debe ingresar un nombre de usuario.", 403)
# Ensure password was submitted
elif not request.form.get("password"):
return apology("Debe ingresar una contraseña.", 403)
# Query database for username
rows = db.execute("SELECT * FROM usuarios WHERE username = :username",
username=request.form.get("username"))
# Ensure username exists and password is correct
if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")):
return apology("Usuario o contraseña incorrectos", 403)
# Remember which user has logged in
session["user_id"] = rows[0]["username"]
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
#app.route("/logout")
def logout():
"""Log user out"""
# Forget any user_id
session.clear()
# Redirect user to login form
return redirect("/")
#app.route("/victima", methods=["GET", "POST"])
def victima():
if request.method == "POST":
if not (request.form.get("nombreescuela" and "curso" and "box")):
return apology("Debes completar todo el formulario.")
if not (len(request.form.get("curso")) == 2):
return apology("Ingrese corectamente el curso (no mas de 2 digitos). El primero debe ser un numero y el segundo la letra de su division. Ejemplo: 5A | (si su colegio no tiene division ingrese el numero acompañado de una x. Ejemplo: 5x) | ")
if not ((request.form.get("curso")[0] == "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8" or "9") and (request.form.get("curso")[1].isalpha())):
return apology("Ingrese el curso correctamente. No se aceptan mas de 2 digitos. El primero debe ser un numero y el segundo la letra de su division. Ejemplo: 5A | (si su colegio no tiene division ingrese el numero acompañado de una x. Ejemplo: 5x) | ")
db.execute("INSERT INTO victimas (escuela, curso, hecho) VALUES(:escuela, :curso, :hecho)", escuela=request.form.get(
"nombreescuela"), curso=request.form.get("curso").upper(), hecho=request.form.get("box"))
flash("Formulario enviado con éxito!")
return redirect("/")
else:
return render_template("victima.html")
#app.route("/testigo", methods=["GET", "POST"])
def testigo():
if request.method == "POST":
if not (request.form.get("nombreescuela" and "curso" and "victima" and "box")):
return apology("Debes completar todo el formulario.")
if not (len(request.form.get("curso")) == 2):
return apology("Ingrese corectamente el curso. No mas de 2 digitos. El primero debe ser un numero y el segundo la letra de su division. Ejemplo: 5A | (si su colegio no tiene division ingrese el numero acompañado de una x. Ejemplo: 5x) | ")
if not ((request.form.get("curso")[0] == "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8" or "9") and (request.form.get("curso")[1].isalpha())):
return apology("Ingrese el curso correctamente. No se aceptan mas de 2 digitos. El primero debe ser un numero y el segundo la letra de su division. Ejemplo: 5A | (si su colegio no tiene division ingrese el numero acompañado de una x. Ejemplo: 5x) | ")
db.execute("INSERT INTO testigos (escuela, curso, victima, hecho) VALUES(:escuela, :curso, :victima, :hecho)", escuela=request.form.get(
"nombreescuela"), curso=request.form.get("curso").upper(), victima=request.form.get("victima"), hecho=request.form.get("box"))
flash("Formulario enviado con éxito!")
return redirect("/")
else:
return render_template("testigo.html")
#app.route("/reportesrecibidos", methods=["GET", "POST"])
#login_required
def reportesrecibidos():
return render_template("reportesrecibidos.html")
#app.route("/tablavictimas")
#login_required
def tablavictimas():
hechos = db.execute("SELECT * FROM victimas WHERE escuela = :escuela", escuela=session["user_id"])
return render_template("tablavictimas.html", escuela=escuela)
#app.route("/tablatestigos")
#login_required
def tablatestigos():
hechos = db.execute("SELECT * FROM testigos WHERE escuela = :escuela", escuela=session["user_id"])
return render_template("tablatestigos.html", escuela=escuela)
Error messages:
KeyError: 'user_id' in line 232 hechos = db.execute("SELECT * FROM
victimas WHERE escuela = :escuela", escuela=session["user_id"])
Sometimes this error also appears
NameError: name 'escuela' is not defined in line 241, in
tablatestigos return render_template("tablatestigos.html",
escuela=escuela)

You have this error:
NameError: name 'escuela' is not defined in line 241, in tablatestigos
return render_template("tablatestigos.html", escuela=escuela)
because escuela is not defined. I think the error message is very clear. Anyway, to solve this problem, you need to define escuela like this:
#app.route("/tablatestigos")
#login_required
def tablatestigos():
escuela = session["user_id"]
hechos = db.execute("SELECT * FROM testigos WHERE escuela = :escuela",
escuela=escuela)
return render_template("tablatestigos.html", escuela=escuela)
The second error:
KeyError: 'user_id' in line 232 hechos = db.execute("SELECT * FROM
victimas WHERE escuela = :escuela", escuela=session["user_id"])
is raised because session["user_id"] does not exist. There are many reasons for this: First, may be the user is not logged in. So you may have a problem in the decorator #login_required. Second, may be you did not define a secret_key for your application. In this case, you will lost your session content after every page refresh. To solve this issue, you need to define a secret_key for your application in the main file:
app = Flask('application')
app.secret_key = "some secret key"
Note that there are more secure solution to define a secret_key for your application but this is the easiest solution.

Related

With Django EmailMessage, why headers keys and values sometimes display and sometimes don't?

I am utilizing Email Message from django.core.mail. I am trying to include headers in messages that I want to send. But in some cases, the first header line does not appear in my message. Why ?
Example with an issue
In the following case, I have an issue :
views.py
from django.shortcuts import render, redirect
from django.core.mail import send_mail, EmailMessage
from django.contrib import messages
from django import forms
from . forms import ContactMessageForm
def contact_form(request):
form = ContactMessageForm(request.POST or None)
context = {'form':form}
if request.method == 'POST':
if form.is_valid():
contact_form = form.save()
contact_form = ContactMessageForm()
first_name = form.cleaned_data["first_name"]
last_name = form.cleaned_data["last_name"]
email = form.cleaned_data["email"]
order_number = form.cleaned_data["order_number"]
subject = form.cleaned_data["subject"]
cc = form.cleaned_data["cc"]
message = form.cleaned_data["message"]
full_name = first_name + " " + last_name
objet = ""
if order_number == None:
objet = subject
else:
objet = subject + ' / ' + order_number
email_msg = EmailMessage(
'[TITLE] : ' + objet,
message,
'foo#foo.fr',
['foo#foo.fr'],
reply_to = [email],
headers = {
"Exp ": 'header 1 value',
"Prenom et Nom ": full_name,
"Objet du message ": str(subject),
"Testing header 4 key": 'header 4 value',
},
)
email_msg.send()
if cc == True:
msg = '''
Bonjour,
Nous avons bien reçu votre email. Nous vous répondrons dans les plus brefs délais.
Voici le message que vous nous avez envoyé. \n \n
'''
msg = msg + message
send_mail(
'[TITLE] : ' + subject + ' / ' + order_number,
msg,
'foo#foo.fr',
[email],
fail_silently=False,
)
messages.success(request, 'Email envoyé')
return redirect('store:home')
else:
return render(request, 'contact/contact-form.html', context)
else:
return render(request, 'contact/contact-form.html', context)
The first line of the header does not show. "Exp", which is the key, and "header 1 value", which is the value do not appear... The rest of the header displays correctly.
Example with NO issue
In the following case, everything works well.
views.py
from django.shortcuts import render, redirect
from django.core.mail import send_mail, EmailMessage
from django.contrib import messages
from django import forms
from . forms import ContactMessageForm
def contact_form(request):
form = ContactMessageForm(request.POST or None)
context = {'form':form}
if request.method == 'POST':
if form.is_valid():
contact_form = form.save()
contact_form = ContactMessageForm()
first_name = form.cleaned_data["first_name"]
last_name = form.cleaned_data["last_name"]
email = form.cleaned_data["email"]
order_number = form.cleaned_data["order_number"]
subject = form.cleaned_data["subject"]
cc = form.cleaned_data["cc"]
message = form.cleaned_data["message"]
full_name = first_name + " " + last_name
objet = ""
if order_number == None:
objet = subject
else:
objet = subject + ' / ' + order_number
email_msg = EmailMessage(
'[TITLE] : ' + objet,
message,
'foo#foo.fr',
['foo#foo.fr'],
reply_to = [email],
headers = {
"header 1 key ": 'header 1 value',
"Prenom et Nom ": full_name,
"Objet du message ": str(subject),
"header 4 key": 'header 4 value',
},
)
email_msg.send()
if cc == True:
msg = '''
Bonjour,
Nous avons bien reçu votre email. Nous vous répondrons dans les plus brefs délais.
Voici le message que vous nous avez envoyé. \n \n
'''
msg = msg + message
send_mail(
'[TITLE] : ' + subject + ' / ' + order_number,
msg,
'foo#foo.fr',
[email],
fail_silently=False,
)
messages.success(request, 'Email envoyé')
return redirect('store:home')
else:
return render(request, 'contact/contact-form.html', context)
else:
return render(request, 'contact/contact-form.html', context)
header 1 key and header 1 value do appear in the message, as the others keys and values of the header.
For information, I have replaced my email address with foo#foo.fr for privacy matters. But I confirm that I have received the messages on my actual email address.

How to add exception to a dictionary if the result is useless for my data?

So I have this code to get the id of a person and check if the person exists in a database. The code works but I forgot to add an exception for people who exist but their id is not a "useful" one.
I tried adding an exception to my code that says:
except cuit == "CUIL":
print("it's not a cuit")
But this is ignored and I get the data anyway even though I don't want it. So what's a better way of doing it?
The info is in
response["persona"]["tipoClave"]
This gives two results: "CUIL" (not useful) and "CUIT" (useful). So how do I prevent the useless ids to be passed as useful?
This is the code:
class ConstanciaInscripcion(FormView):
def get(self, request):
return render(request, 'app/constancia-inscripcion.html')
def post(self,request):
form = MonotributoForm(request.POST)
email = request.POST['Email']
#Verificar cuit en padron13 una vez que es ingresado
cuit_r = int(request.POST["CUIT"])
response = get_persona(cuit_r)
try:
nombre = response["persona"]["nombre"]
apellido = response["persona"]["apellido"]
cuit = response["persona"]["tipoClave"]
except KeyError:
nombre, apellido = None, None
print("El CUIT ingresado es incorrecto")
except TypeError:
nombre, apellido = None, None
print("El CUIT ingresado es incorrecto")
except cuit == "CUIL":
print("it's not a cuit")
else:
print(nombre, apellido)
if form.is_valid():
cuit = form.cleaned_data.get('CUIT')
email = form.cleaned_data.get('Email')
cuit.save()
email.save()
return render(request, 'app/constancia-inscripcion.html')
return render(request, 'app/constancia-inscripcion.html')
That's not how "except" works. Except catches specific exceptions that are thrown with the "raise" statement. You need:
try:
nombre = response["persona"]["nombre"]
apellido = response["persona"]["apellido"]
cuit = response["persona"]["tipoClave"]
if cuit != "CUIL":
print("it's not a cuit")
except KeyError:
nombre, apellido = None, None
print("El CUIT ingresado es incorrecto")
except TypeError:
nombre, apellido = None, None
print("El CUIT ingresado es incorrecto")
...

Django cannot serialize into migration file

Hi there i'm having problems when trying to use the command makemigrations with manage.py.
The output is the following:
Migrations for 'reg':
reg\migrations\0012_auto_20190917_1711.py
- Remove field Products from tenant
- Add field products to tenant
- Alter field productos on preaprobado
- Alter field tenant_id on preaprobado
- Alter field CMS_id on producto
- Alter field CMS_id on tenant
Traceback errors
ValueError: Cannot serialize: <Producto: Basico - ['IPTEL', 'Rocstar', 'Test_DVT']>
There are some values Django cannot serialize into migration files.
For more, see https://docs.djangoproject.com/en/2.2/topics/migrations/#migration-serializing
The thing is that the entire app works just fine but for some reason i can't understand i cannot migrate the db.
Here is the models.py:
class Producto(models.Model):
Name = models.CharField(max_length = 50, unique = True)
CMS_id = models.PositiveIntegerField(unique = True)
def __str__(self):
#Toma los tenants que tienen el producto asignado por el nombre y forma una lista de los nombres de los tenants
#para que aparezcan al lado del nombre del producto
tenants_with_product = Tenant.objects.filter(products__Name = self.Name)
tenants_dict = tenants_with_product.in_bulk(field_name = "Name")
tenants_list = []
for tenant_name in tenants_dict.keys():
tenants_list.append(tenant_name)
return(self.Name + " - " + tenants_list.__str__())
class Tenant(models.Model):
Name = models.CharField(max_length = 30, unique = True)
Enabled = models.BooleanField(default = False)
CMS_id = models.PositiveIntegerField(unique = True)
Logo = models.ImageField(upload_to = "Logos/", blank = True)
Icon = models.ImageField(upload_to = "Icons/", blank = True)
Domain = models.URLField(default = "http://localhost:8000")
Master = models.BooleanField(default = False)
products = models.ManyToManyField(Producto, related_name = "tenants")
def __str__(self):
return(self.Name)
# Override del metodo que salva en la db para que si se quiere salvar un Tenant con Master = True y
# existe un Tenant con mismo dominio y Master = True no pueda salvar
def save(self, *args, **kwargs):
#busca tenant con mismo dominio y Master = True
try:
master_tenant = Tenant.objects.filter(Domain = self.Domain).get(Master = True)
#Si el tenant encontrado es el que se quiere salvar chequeo que sea Master = True y salvo
#sino pido Master = True. Chequea tambien que el master tenga logo e icono si o si
if master_tenant.id == self.id:
if self.Master:
if self.Logo != "" and self.Icon != "":
super(Tenant, self).save(*args, **kwargs)
else:
raise ValidationError({"Logo" : "Logo required", "Icon" : "Icon rquired"})
else:
raise ValidationError({"Master" : "At least one Master per Domain"})
else:
#Si no es el Master = True del dominio y Master = False guarda, sino error
if self.Master:
if self.Logo != "" and self.Icon != "":
super(Tenant, self).save(*args, **kwargs)
else:
raise ValidationError({"Logo" : "Logo required", "Icon" : "Icon rquired"})
else:
super(Tenant, self).save(*args, **kwargs)
#Si no existe tenant con mismo Domain y Master = True, Se fija que Master = True y que tenga logo e icono y salva, sino, error
except Tenant.DoesNotExist:
if self.Master:
if self.Logo != "" and self.Icon != "":
super(Tenant, self).save(*args, **kwargs)
else:
raise ValidationError({"Logo" : "Logo required", "Icon" : "Icon rquired"})
else:
raise ValidationError({"Master" : "At least one Master per Domain"})
class Preaprobado(models.Model):
codigo = models.CharField(max_length = 100)
tenant_id = models.ForeignKey(Tenant, on_delete = models.CASCADE, related_name = "tenant")
can_register = models.BooleanField(default = True)
is_registered = models.BooleanField(default = False)
productos = models.ManyToManyField(Producto, related_name = "preaprobados", default = Producto.objects.get(id = 1))
def __str__(self):
return(self.codigo + "-" + self.tenant_id.Name)
class Meta():
#No permite un par codigo-tenant repetido dentro del modelo Preaprobado
constraints = [
models.UniqueConstraint(fields = ["codigo", "tenant_id"], name = "par código-Tenant únicos"),
]
Any help is welcomed since i actually can't find what is wrong with the code. Not even in the documentation. I'm new with Django so maybe the solution is pretty easy but i can't find it.

Cannot register new user because of utf-8 validation error on heroku

I have deployed a flask application on heroku but I am facing an UTF-8 validation error when trying to register a new user. Everything is working fine on local, so I don't know what is causing this.
Here is my code for the route:
# REGISTER
#bp.route('/register', methods = ['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = RegistrationForm()
if form.validate_on_submit():
user = User(username = form.username.data)
password = form.password.data
password_validation = password_check(password)
if not password_validation['password_ok']:
flash("Votre mot de passe n'est pas sécurisé !")
if password_validation['length_error']:
flash("Votre mot de passe doit comporter au moins 8 caractères !")
if password_validation['digit_error']:
flash("Votre mot de passe doit comporter au moins 1 chiffre !")
if password_validation['uppercase_error']:
flash("Votre mot de passe doit comporter au moins 1 majuscule !")
if password_validation['lowercase_error']:
flash("Votre mot de passe doit comporter au moins 1 minuscule !")
if password_validation['symbol_error']:
flash("Votre mot de passe doit comporter au moins 1 caractère spécial !")
return redirect(url_for('auth.register'))
user.set_password(password)
user.send_confirmation_email = datetime.now()
db.session.add(user)
db.session.commit()
send_confirmation_email(user.username)
flash('Félicitations, vous êtes désormais enregistré ! Veuillez consulter vos mails pour confirmer votre adresse mail !')
return redirect(url_for('auth.login'))
return render_template('auth/register.html', title = 'Inscription', form = form)
Here is my code for the form:
class RegistrationForm(FlaskForm):
username = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Mot de passe', validators=[DataRequired()])
password2 = PasswordField(
'Confirmation du mot de passe', validators=[DataRequired(), EqualTo('password')])
recaptcha = RecaptchaField()
submit = SubmitField('S\'enregistrer')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
is_client = client_mail(username.data)
if is_client == False:
raise ValidationError('Nous sommes désolé mais vous n\'êtes pas l\'un de nos clients.')
if user is not None:
if not user.email_confirmed:
send_confirmation_email(user.username)
raise ValidationError('Une nouveau mail de confirmation vous a été envoyé.')
else:
raise ValidationError('Cette addresse mail est déjà utilisée, veuillez en saisir une nouvelle.')
Anyone has an idea what is the problem here?
I had a look with the heroku logs --tail command but could not find any errors.
EDIT
Here is the code to check the password:
def password_check(password):
length_error = len(password) < 8
digit_error = re.search(r"\d", password) is None
uppercase_error = re.search(r"[A-Z]", password) is None
lowercase_error = re.search(r"[a-z]", password) is None
symbol_error = re.search(r"\W", password) is None
password_ok = not (length_error or digit_error or uppercase_error or lowercase_error or symbol_error)
return {
'password_ok': password_ok,
'length_error': length_error,
'digit_error': digit_error,
'uppercase_error': uppercase_error,
'lowercase_error': lowercase_error,
'symbol_error': symbol_error
}
After some more digging I finally found the problem.
It was in my client_mail() function: I was reading a CSV file without any encoding options.
with open(csv_file) as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
for (key, val) in row.items():
if client_company in val:
is_client = True
I added yield {unicode(key, 'utf-8'):unicode(value, 'utf-8') for key, value in row.iteritems()} after the first for statement and it's working fine now.

Python Psycopg2 cursor.execute returning None

Hello I'm working on a script in Python that will connect to a db retrieve some information and send emails. I'have a problem with queries done with Psycopg.
I'would like to retrieve all the users where created_at = nb_days. My query work very good in navicat/pgadmin and I'have 53 records with the query :
select a.account_name, a.email, a.user_id, a.locale, a.firstname from v_accounts a where date(a.created_at) = date(current_date - interval '2 days')
But when I execute my script I have None as result of the query. This is my script class :
import psycopg2
class MyDatabase(object):
db_name='you'
user='will'
pw='never'
host='know'
port='it'
def __init__(self, db=db_name, user=user, password=pw, host=host, port=port):
"""Connection to db - creation of the cursor"""
try:
self.baseDonn = psycopg2.connect(host=host, port=port, database=db, user=user,password=password)
except Exception as err:
print('La connexion avec la base de données à échoué : Erreur détéctée : %s' % err)
else:
self.cursor=self.baseDonn.cursor() # Création du curseur
def get_data_from_accounts(self,nb_days):
''' Method that retrieves data from all accounts that were created nb_days before today '''
sql="select a.account_name,u.email, u.user_id,u.locale, u.firstname from accounts a inner join account_users au on a.account_id=au.account_id inner join users u on au.user_id=u.user_id where date(a.created_at) = date(current_date - interval '%s days');"
print(sql)
data=(nb_days,)
try:
records = self.cursor.execute(sql,data)
print('cursor-execute={}'.format(records))
except Exception as err:
print("La requete n'est pas passée, erreur={}".format(err))
else:
return records
This is the main part
from my_db import MyDatabase
database=MyDatabase()
# On va récupérer les données des nouveaux accounts d'y a un jours
days_ago_2=database.get_data_from_accounts(2)
for personne_1 in days_ago_2:
# data
#account_name=personne_1[0]
email=personne_1[1]
user_id=personne_1[2]
locale=personne_1[3]
firstname='' if personne_1[4] is None else personne_1[4]
language = locale.split('_')[1]
activation_token= database.get_activation_token(user_id)
subject = call_to_template2(firstname, language,activation_token)['subject']
content = call_to_template2(firstname, language,activation_token)['content']
print('EMAIL={} - ID={} - LANGUE={} - FIRSTNAME={}'.format(email, user_id, language, firstname))
#send_data(qui_envoie, email, subject, content, token, language)
And my error is on the line for personne_1 in days_ago_2: because None object is not iterable. And I've saw that the result of my query get_data_from_accounts(2) = None
cursor.execute allways returns None. You need to fetch the record set:
try:
self.cursor.execute(sql,data)
records = self.cursor.fetchall()

Categories

Resources