Skip to content
Snippets Groups Projects
Commit 9295df9b authored by Benjamin Bertrand's avatar Benjamin Bertrand
Browse files

Add created_at/updated_at/user_id columns to tables

- This will help tracking who and what was created / changed
- Move fetch_current_user_id to utils.py
- Make ItemComment inherit from CreatedMixin
parent e5051986
No related branches found
No related tags found
No related merge requests found
......@@ -12,7 +12,7 @@ This module implements the inventory blueprint.
import sqlalchemy as sa
from flask import (Blueprint, render_template, jsonify, session,
request, redirect, url_for, flash, current_app)
from flask_login import login_required, current_user
from flask_login import login_required
from .forms import AttributeForm, ItemForm, CommentForm
from ..extensions import db
from ..decorators import login_groups_accepted
......@@ -24,11 +24,11 @@ bp = Blueprint('inventory', __name__)
@bp.route('/_retrieve_items')
@login_required
def retrieve_items():
items = models.Item.query.order_by(models.Item._created)
items = models.Item.query.order_by(models.Item.created_at)
data = [[item.id,
item.ics_id,
utils.format_field(item._created),
utils.format_field(item._updated),
utils.format_field(item.created_at),
utils.format_field(item.updated_at),
item.serial_number,
utils.format_field(item.manufacturer),
utils.format_field(item.model),
......@@ -92,7 +92,6 @@ def comment_item(ics_id):
form = CommentForm()
if form.validate_on_submit():
comment = models.ItemComment(text=form.text.data,
user_id=current_user.id,
item_id=item.id)
db.session.add(comment)
db.session.commit()
......
......@@ -12,6 +12,7 @@ This module implements the models used in the app.
import ipaddress
import qrcode
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.dialects import postgresql
from sqlalchemy.orm import validates
from sqlalchemy.ext.associationproxy import association_proxy
......@@ -106,7 +107,6 @@ class User(db.Model, UserMixin):
groups = association_proxy('grp', 'name',
creator=find_or_create_group)
tokens = db.relationship("Token", backref="user")
comments = db.relationship('ItemComment', backref='user')
def get_id(self):
"""Return the user id as unicode
......@@ -221,15 +221,32 @@ class Status(QRCodeMixin, db.Model):
items = db.relationship('Item', back_populates='status')
class Item(db.Model):
class CreatedMixin:
id = db.Column(db.Integer, primary_key=True)
created_at = db.Column(db.DateTime, default=utcnow())
updated_at = db.Column(db.DateTime, default=utcnow(), onupdate=utcnow())
# Using ForeignKey and relationship in mixin requires the @declared_attr decorator
# See http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/mixins.html
@declared_attr
def user_id(cls):
return db.Column(db.Integer, db.ForeignKey('user_account.id'),
nullable=False, default=utils.fetch_current_user_id)
@declared_attr
def user(cls):
return db.relationship('User')
class Item(CreatedMixin, db.Model):
__versioned__ = {
'exclude': ['_created', 'ics_id', 'serial_number',
'exclude': ['created_at', 'ics_id', 'serial_number',
'manufacturer_id', 'model_id']
}
# WARNING! Inheriting id from CreatedMixin doesn't play well with
# SQLAlchemy-Continuum. It has to be defined here.
id = db.Column(db.Integer, primary_key=True)
_created = db.Column(db.DateTime, default=utcnow())
_updated = db.Column(db.DateTime, default=utcnow(), onupdate=utcnow())
ics_id = db.Column(db.Text, unique=True, nullable=False, index=True)
serial_number = db.Column(db.Text, nullable=False)
manufacturer_id = db.Column(db.Integer, db.ForeignKey('manufacturer.id'))
......@@ -278,8 +295,8 @@ class Item(db.Model):
'model': utils.format_field(self.model),
'location': utils.format_field(self.location),
'status': utils.format_field(self.status),
'updated': utils.format_field(self._updated),
'created': utils.format_field(self._created),
'updated_at': utils.format_field(self.updated_at),
'created_at': utils.format_field(self.created_at),
'parent': utils.format_field(self.parent),
}
if long:
......@@ -300,7 +317,7 @@ class Item(db.Model):
else:
parent = Item.query.get(version.parent_id)
versions.append({
'updated': utils.format_field(version._updated),
'updated_at': utils.format_field(version.updated_at),
'location': utils.format_field(version.location),
'status': utils.format_field(version.status),
'parent': utils.format_field(parent),
......@@ -308,16 +325,12 @@ class Item(db.Model):
return versions
class ItemComment(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=utcnow(), index=True)
class ItemComment(CreatedMixin, db.Model):
text = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user_account.id'), nullable=False)
item_id = db.Column(db.Integer, db.ForeignKey('item.id'), nullable=False)
class Network(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Network(CreatedMixin, db.Model):
vlan_name = db.Column(CIText, nullable=False, unique=True)
vlan_id = db.Column(db.Integer, nullable=False, unique=True)
address = db.Column(postgresql.CIDR, nullable=False, unique=True)
......@@ -455,8 +468,7 @@ class Tag(QRCodeMixin, db.Model):
pass
class Host(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Host(CreatedMixin, db.Model):
name = db.Column(db.Text, nullable=False, unique=True)
type = db.Column(db.Text)
description = db.Column(db.Text)
......@@ -479,8 +491,7 @@ class Host(db.Model):
return lower_string
class Interface(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Interface(CreatedMixin, db.Model):
network_id = db.Column(db.Integer, db.ForeignKey('network.id'), nullable=False)
ip = db.Column(postgresql.INET, nullable=False, unique=True)
name = db.Column(db.Text, nullable=False, unique=True)
......@@ -565,8 +576,7 @@ class Mac(db.Model):
return d
class Cname(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Cname(CreatedMixin, db.Model):
name = db.Column(db.Text, nullable=False, unique=True)
interface_id = db.Column(db.Integer, db.ForeignKey('interface.id'), nullable=False)
......@@ -581,9 +591,8 @@ class Cname(db.Model):
}
class NetworkScope(db.Model):
class NetworkScope(CreatedMixin, db.Model):
__tablename__ = 'network_scope'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(CIText, nullable=False, unique=True)
first_vlan = db.Column(db.Integer, nullable=False, unique=True)
last_vlan = db.Column(db.Integer, nullable=False, unique=True)
......
......@@ -20,31 +20,15 @@ The `user_id` column is automatically populated when the transaction object is c
"""
from flask.globals import _app_ctx_stack, _request_ctx_stack
from sqlalchemy_continuum.plugins import Plugin
from flask_login import current_user
from flask_jwt_extended import get_current_user
def fetch_current_user_id():
# Return None if we are outside of request context.
if _app_ctx_stack.top is None or _request_ctx_stack.top is None:
return None
# Try to get the user from both flask_jwt_extended and flask_login
user = get_current_user() or current_user
try:
return user.id
except AttributeError:
return None
from . import utils
class FlaskUserPlugin(Plugin):
def __init__(
self,
current_user_id_factory=None,
):
def __init__(self, current_user_id_factory=None):
self.current_user_id_factory = (
fetch_current_user_id if current_user_id_factory is None
utils.fetch_current_user_id if current_user_id_factory is None
else current_user_id_factory
)
......
......@@ -17,9 +17,9 @@
<dt class="col-sm-3">ICS id</dt>
<dd class="col-sm-9">{{ item.ics_id }}</dd>
<dt class="col-sm-3">Created</dt>
<dd class="col-sm-9">{{ format_datetime(item._created) }}</dd>
<dd class="col-sm-9">{{ format_datetime(item.created_at) }}</dd>
<dt class="col-sm-3">Updated</dt>
<dd class="col-sm-9">{{ format_datetime(item._updated) }}</dd>
<dd class="col-sm-9">{{ format_datetime(item.updated_at) }}</dd>
<dt class="col-sm-3">Serial number</dt>
<dd class="col-sm-9">{{ item.serial_number }}</dd>
<dt class="col-sm-3">Manufacturer</dt>
......@@ -49,7 +49,7 @@
{% for comment in item.comments %}
<div class="card border-light mb-3">
<div class="card-header">
{{ comment.user }} commented on {{ format_datetime(comment.timestamp) }}
{{ comment.user }} commented on {{ format_datetime(comment.created_at) }}
</div>
<div class="card-body item-comment">{{ comment.text }}</div>
</div>
......@@ -73,7 +73,7 @@
<tbody>
{% for version in item.history() %}
<tr>
<td>{{ version['updated'] }}</td>
<td>{{ version['updated_at'] }}</td>
<td>{{ version['location'] }}</td>
<td>{{ version['status'] }}</td>
<td>{{ link_to_item(version['parent']) }}</td>
......
......@@ -13,6 +13,22 @@ import base64
import datetime
import io
import sqlalchemy as sa
from flask.globals import _app_ctx_stack, _request_ctx_stack
from flask_login import current_user
from flask_jwt_extended import get_current_user
def fetch_current_user_id():
"""Retrieve the user_id from flask_jwt_extended (API) or flask_login (web UI)"""
# Return None if we are outside of request context.
if _app_ctx_stack.top is None or _request_ctx_stack.top is None:
return None
# Try to get the user from both flask_jwt_extended and flask_login
user = get_current_user() or current_user
try:
return user.id
except AttributeError:
return None
class CSEntryError(Exception):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment