commit 04b5110ed27af33fe39097e800a429eb89943a56
parent abdfbba06bdd861faa37847da1cf554e9a808b58
Author: NibbaNamedHassan <[email protected]>
Date: Thu, 12 May 2022 13:51:27 +0200
Merge branch 'master' of https://github.com/friedelschoen/muizenval.io
Diffstat:
13 files changed, 205 insertions(+), 40 deletions(-)
diff --git a/create-db.py b/create-db.py
@@ -0,0 +1,5 @@
+from server.app import db
+import server.models
+
+db.create_all()
+db.session.commit()
diff --git a/readme.md b/readme.md
@@ -1,5 +1,7 @@
# REPOSITORY VOOR ONS IOT-PROJECT (5GRONINGEN)
+> Hamdi Hassan, Loes Hoogstra, Gerco van Woudenberg, Friedel Schon
+
## De server runnen
Dit is een dev-server, dus run je met `debug=True`-flag!
diff --git a/server/app.py b/server/app.py
@@ -3,9 +3,11 @@ from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
+
app = Flask(__name__)
app.config['SECRET_KEY'] = 'iot_project'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
+app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
diff --git a/server/forms.py b/server/forms.py
@@ -1,17 +1,23 @@
-from flask_login import current_user
+import re
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileField
-from wtforms import BooleanField, HiddenField, PasswordField, SelectField, StringField, SubmitField, TextAreaField
+from wtforms import BooleanField, HiddenField, PasswordField, SelectField, StringField, SubmitField, IntegerField
from wtforms.validators import DataRequired, Email, EqualTo, Length, ValidationError
-from .models import User
+from .models import User, UserType
""" registration form for register.html """
class RegistrationForm(FlaskForm):
- name = StringField('Naam', validators=[ DataRequired(), Length(min=2, max=20) ])
+ name = StringField('Naam', validators=[ DataRequired(), Length(min=5, max=20) ])
email = StringField('E-Mail', validators=[ DataRequired(), Email() ])
password = PasswordField('Wachtwoord', validators=[ DataRequired() ])
confirm_password = PasswordField('Wachtwoord herhalen', validators=[ DataRequired(), EqualTo('password') ])
+ phone = StringField('Telefoon', validators=[ DataRequired(), Length(min=5) ])
+ street = StringField('Straat', validators=[ DataRequired() ])
+ housenumber = IntegerField('Huisnummer', validators=[ DataRequired() ])
+ postcode = StringField('Postcode', validators=[ DataRequired() ])
+ place = StringField('Plaats', validators=[ DataRequired() ])
+ catcher_code = StringField('VangerCode', validators=[ DataRequired(), Length(min=5, max=5) ])
submit = SubmitField('Registeren')
""" validates whether name is already in use """
@@ -22,7 +28,21 @@ class RegistrationForm(FlaskForm):
""" validates whether e-mail is already in use """
def validate_email(self, email):
if User.query.filter_by(email=email.data).first():
- raise ValidationError('Deze e-mail bestaat al, log in als dat uw e-mail is')
+ raise ValidationError('Deze e-mail bestaat al, log in als dat uw e-mail is.')
+
+ def validate_phone(self, phone):
+ for c in phone.data:
+ if c not in '0123456789 -':
+ raise ValidationError('Dit belnummer is niet geldig.')
+
+ def validate_postcode(self, code):
+ if len(code.data) != 6 or not code.data[0:4].isnumeric() or not code.data[4:6].isalpha():
+ raise ValidationError('De postcode is niet geldig.')
+
+
+ def validate_catcher_code(self, code):
+ if not User.query.filter_by(type=UserType.CATCHER, catcher_code=code.data).first():
+ raise ValidationError('De rattenvanger is niet bekennt, hebt u de code juist ingevoerd?')
""" login form for login.html """
diff --git a/server/models.py b/server/models.py
@@ -1,5 +1,4 @@
-from datetime import datetime
-
+from enum import Enum
from flask_login import UserMixin
from .app import db, login_manager
@@ -10,23 +9,41 @@ def load_user(user_id):
return User.query.get(int(user_id))
+class UserType(Enum):
+ ADMIN = 0
+ MANAGER = 1
+ TECHNICIAN = 2
+ CATCHER = 3
+ CLIENT = 4
+
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
- type = db.Column(db.String(7), nullable=False, default="guest") # guest, client, catcher, admin
+ type = db.Column(db.Enum(UserType))
email = db.Column(db.String(120), unique=True, nullable=False)
name = db.Column(db.String(20), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
+ phone = db.Column(db.Text, nullable=False)
+ address = db.Column(db.Text)
+
+ manager = db.Column(db.Integer, db.ForeignKey('user.id')) # set if technician, catcher, user
+ catcher_code = db.Column(db.String(5)) # set if catcher
+ catcher = db.Column(db.Integer, db.ForeignKey('user.id')) # set if user
-class Home(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- owner = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
- catcher = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
- adress = db.Column(db.Text, nullable=False)
class Trap(db.Model):
id = db.Column(db.Integer, primary_key=True)
mac = db.Column(db.String(16), unique=True, nullable=False)
- home = db.Column(db.Integer, db.ForeignKey('home.id'), nullable=False)
- last_heartbeat = db.Column(db.Integer, nullable=True, default=0)
+ name = db.Column(db.Text)
+ owner = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
+ last_heartbeat = db.Column(db.DateTime, nullable=True, default=0)
caught = db.Column(db.Boolean, nullable=False, default=False)
+
+ def pretty_mac(self):
+ upper = self.mac.upper()
+ return ':'.join([ upper[i] + upper[i+1] for i in range(0, len(upper), 2) ])
+
+ def status_color(self):
+ if self.caught:
+ return '#f4a900'
+ return 'currentColor'
diff --git a/server/routes.py b/server/routes.py
@@ -1,3 +1,4 @@
+from operator import or_
import os
import secrets
@@ -9,7 +10,7 @@ from datetime import datetime
from .app import app, bcrypt, db
from .forms import LoginForm, RegistrationForm, UpdateAccountForm
-from .models import User
+from .models import Trap, User, UserType
""" index.html (home-page) route """
@@ -104,6 +105,16 @@ def account():
image_file = url_for('static', filename='profile_pics/' + current_user.image_file)
return render_template('account.html', title='Profiel', image_file=image_file, form=form)
[email protected]('/dashboard')
+@login_required
+def dashboard():
+ query = [ current_user ]
+ if current_user.type == UserType.CATCHER:
+ query += list(User.query.filter_by(catcher=current_user.id))
+
+ traps = [ trap for user in query for trap in Trap.query.filter_by(owner=user.id) ]
+
+ return render_template('dashboard.html', title='Dashboard', traps=traps)
""" 404 not found handler """
@app.errorhandler(404)
diff --git a/server/site.db b/server/site.db
Binary files differ.
diff --git a/server/static/main.css b/server/static/main.css
@@ -8,6 +8,7 @@ body {
code {
font-family: 'Source Code Pro';
+ color: inherit;
}
h1, h2, h3, h4, h5, h6 {
diff --git a/server/templates/dashboard.html b/server/templates/dashboard.html
@@ -0,0 +1,45 @@
+{% extends "layout.html" %}
+{% block content %}
+<article class="media content-section">
+ <div class="media-body">
+ <h2><b>Dit zijn uw muizenvallen</b></h2>
+ <p>
+ Klik op de titel van een muizenval om de instellingen in te zien!
+ </p>
+ </div>
+</article>
+{% for home, trap in traps %}
+<article class="media content-section">
+ <div class="media-body">
+ <h3><a class="article-title" href="#">
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="{{ trap.status_color() }}"
+ class="bi bi-circle-fill" viewBox="0 0 20 20">
+ <circle cx="10" cy="10" r="10" />
+ </svg>
+ -
+ {% if trap.name %}
+ {{ trap.name }}
+ {% else %}
+ <code>[{{ trap.pretty_mac() }}]</code>
+ {% endif %}
+ <small>van {{ home.owner_class().name }}</small>
+ </a>
+ </h3>
+ {% if trap.name %}
+ <p>
+ <code>[{{ trap.pretty_mac() }}]</code>
+ </p>
+ {% endif %}
+ <p>
+ onderhouden door <b>{{ home.catcher_class().name }}</b>
+ </p>
+ <p>
+ <a class="article-title" href="#">
+ {{ home.street }} {{ home.number }}<br>
+ {{ home.zipcode }} {{ home.place }}
+ </a>
+ </p>
+ </div>
+</article>
+{% endfor %}
+{% endblock content %}
+\ No newline at end of file
diff --git a/server/templates/index.html b/server/templates/index.html
@@ -8,25 +8,4 @@
</p>
</div>
</article>
-{% for course in courses %}
-<article class="media content-section">
- <div class="media-body">
- <h3><a class="article-title" href="{{url_for('course', course_id=course.id)}}">
- {{ course.name }}
- {{ '(ingescheven)' if course.id in subs }}
- </a></h3>
- <p><i>{{ course.description }}</i></p>
- <p>
- wordt gegeven door
- {% for teacher in teachers if teacher.id == course.teacher_id %}
- {{ teacher.name }},
- {% endfor %}
- </p>
- <p>
- elke {{ ['maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'][course.weekday] }}
- {{ course.start }} uur t/m {{ course.end }} uur op locatie: <b>{{ course.location }}</b>
- </p>
- </div>
-</article>
-{% endfor %}
{% endblock content %}
\ No newline at end of file
diff --git a/server/templates/layout.html b/server/templates/layout.html
@@ -9,7 +9,6 @@
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">
- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='openmoji/openmoji.css') }}">
<!-- Google Font: Source Sans Pro -->
<link rel="preconnect" href="https://fonts.googleapis.com">
@@ -29,10 +28,11 @@
<nav class="navbar navbar-expand-md fixed-top">
<div class="container">
<a class="navbar-brand mr-4" href="/">
- <code>muizenval.io</code>
+ <b><code>muizenval.io</code></b>
</a>
<div class="collapse navbar-collapse" id="navbarToggle">
<div class="navbar-nav mr-auto">
+ <a class="nav-item nav-link" href="#">Shop</a>
<a class="nav-item nav-link" href="{{ url_for('about') }}">Over ons</a>
<a class="nav-item nav-link" href="{{ url_for('producten') }}">Producten</a>
</div>
@@ -87,7 +87,7 @@
</li>
{% if current_user.type in [ 'client', 'catcher' ] %}
<li class="list-group-item list-group-item-light">
- <a href="#">Uw muizenvallen</a>
+ <a href="{{ url_for('dashboard') }}">Uw muizenvallen</a>
</li>
{% endif %}
{% if current_user.type == 'catcher' %}
diff --git a/server/templates/register.html b/server/templates/register.html
@@ -58,6 +58,84 @@
{{ form.confirm_password(class="form-control form-control-lg") }}
{% endif %}
</div>
+ <div class="form-group">
+ {{ form.phone.label(class="form-control-label") }}
+ {% if form.phone.errors %}
+ {{ form.phone(class="form-control form-control-lg is-invalid") }}
+ <div class="invalid-feedback">
+ {% for error in form.phone.errors %}
+ <span>{{ error }}</span>
+ {% endfor %}
+ </div>
+ {% else %}
+ {{ form.phone(class="form-control form-control-lg") }}
+ {% endif %}
+ </div>
+ <div class="form-group">
+ {{ form.street.label(class="form-control-label") }}
+ {% if form.street.errors %}
+ {{ form.street(class="form-control form-control-lg is-invalid") }}
+ <div class="invalid-feedback">
+ {% for error in form.street.errors %}
+ <span>{{ error }}</span>
+ {% endfor %}
+ </div>
+ {% else %}
+ {{ form.street(class="form-control form-control-lg") }}
+ {% endif %}
+ </div>
+ <div class="form-group">
+ {{ form.housenumber.label(class="form-control-label") }}
+ {% if form.housenumber.errors %}
+ {{ form.housenumber(class="form-control form-control-lg is-invalid") }}
+ <div class="invalid-feedback">
+ {% for error in form.housenumber.errors %}
+ <span>{{ error }}</span>
+ {% endfor %}
+ </div>
+ {% else %}
+ {{ form.housenumber(class="form-control form-control-lg") }}
+ {% endif %}
+ </div>
+ <div class="form-group">
+ {{ form.postcode.label(class="form-control-label") }}
+ {% if form.postcode.errors %}
+ {{ form.postcode(class="form-control form-control-lg is-invalid") }}
+ <div class="invalid-feedback">
+ {% for error in form.postcode.errors %}
+ <span>{{ error }}</span>
+ {% endfor %}
+ </div>
+ {% else %}
+ {{ form.postcode(class="form-control form-control-lg") }}
+ {% endif %}
+ </div>
+ <div class="form-group">
+ {{ form.place.label(class="form-control-label") }}
+ {% if form.place.errors %}
+ {{ form.place(class="form-control form-control-lg is-invalid") }}
+ <div class="invalid-feedback">
+ {% for error in form.place.errors %}
+ <span>{{ error }}</span>
+ {% endfor %}
+ </div>
+ {% else %}
+ {{ form.place(class="form-control form-control-lg") }}
+ {% endif %}
+ </div>
+ <div class="form-group">
+ {{ form.catcher_code.label(class="form-control-label") }}
+ {% if form.catcher_code.errors %}
+ {{ form.catcher_code(class="form-control form-control-lg is-invalid") }}
+ <div class="invalid-feedback">
+ {% for error in form.catcher_code.errors %}
+ <span>{{ error }}</span>
+ {% endfor %}
+ </div>
+ {% else %}
+ {{ form.catcher_code(class="form-control form-control-lg") }}
+ {% endif %}
+ </div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
diff --git a/test.py b/test.py
@@ -0,0 +1,4 @@
+code = '9939a3'
+
+if len(code) != 6 or not code[0:4].isnumeric() or not code[4:6].isalpha():
+ print('invalid')