From 74437b803bd6cbfff1f6b6fd537db050accd26c5 Mon Sep 17 00:00:00 2001
From: Benjamin Bertrand <benjamin.bertrand@esss.se>
Date: Wed, 19 Jul 2017 16:27:21 +0200
Subject: [PATCH] Fix hash computation in admin view

The hash is supposed to be computed in the __init__ method of Item.
But flask-admin never passes any parameter when creating the model class.
The attributes are changed after creation.

When creating an item in the admin view, we use the on_model_change
method to update the hash.

There might be a better way to avoid this code duplication.
This works for now.
---
 app/admin/views.py | 19 +++++++++++++------
 app/factory.py     |  7 +++----
 app/models.py      |  2 +-
 app/utils.py       |  2 ++
 4 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/app/admin/views.py b/app/admin/views.py
index 465f8d6..5f79881 100644
--- a/app/admin/views.py
+++ b/app/admin/views.py
@@ -11,6 +11,8 @@ This module customizes the admin views.
 """
 from flask_admin.contrib import sqla
 from flask_login import current_user
+from ..models import Item
+from .. import utils
 
 
 class AdminModelView(sqla.ModelView):
@@ -19,9 +21,14 @@ class AdminModelView(sqla.ModelView):
         return current_user.is_authenticated and current_user.is_admin
 
 
-# Here is an example to customize an admin view
-# class ItemAdmin(AdminModelView):
-#     form_columns = ['serial_number', 'vendor', 'model']
-#
-#     def __init__(self, session):
-#         super().__init__(Item, session)
+class ItemAdmin(AdminModelView):
+
+    def __init__(self, session):
+        super().__init__(Item, session)
+
+    def on_model_change(self, form, model, is_created):
+        """Update the hash"""
+        # The hash is supposed to be computed in the __init__ method
+        # of the Item class but flask-admin doesn't pass any parameter
+        # when creating a class - we do it here instead
+        model.hash = utils.compute_hash(model.serial_number)
diff --git a/app/factory.py b/app/factory.py
index b2218cd..c08ff35 100644
--- a/app/factory.py
+++ b/app/factory.py
@@ -13,8 +13,8 @@ import sqlalchemy as sa
 from flask import Flask
 from . import settings
 from .extensions import db, migrate, login_manager, ldap_manager, bootstrap, admin, mail, jwt
-from .models import User, Role, Action, Vendor, Model, Location, Status, Item
-from .admin.views import AdminModelView
+from .models import User, Role, Action, Vendor, Model, Location, Status
+from .admin.views import AdminModelView, ItemAdmin
 from .main.views import bp as main
 from .users.views import bp as users
 from .api.items import bp as api
@@ -95,8 +95,7 @@ def create_app():
     admin.add_view(AdminModelView(Model, db.session))
     admin.add_view(AdminModelView(Location, db.session))
     admin.add_view(AdminModelView(Status, db.session))
-    admin.add_view(AdminModelView(Item, db.session))
-    # admin.add_view(ItemAdmin(db.session))
+    admin.add_view(ItemAdmin(db.session))
 
     app.register_blueprint(main)
     app.register_blueprint(users)
diff --git a/app/models.py b/app/models.py
index ece4168..1ed2925 100644
--- a/app/models.py
+++ b/app/models.py
@@ -179,7 +179,7 @@ class Item(db.Model):
     status = db.relationship('Status', back_populates='items')
     children = db.relationship('Item', backref=db.backref('parent', remote_side=[id]))
 
-    def __init__(self, serial_number='', name=None, vendor=None, model=None, location=None, status=None):
+    def __init__(self, serial_number=None, name=None, vendor=None, model=None, location=None, status=None):
         self.serial_number = serial_number
         self.name = name
         self.vendor = vendor
diff --git a/app/utils.py b/app/utils.py
index 779a6f5..40d9f16 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -39,6 +39,8 @@ class InventoryError(Exception):
 
 
 def compute_hash(string):
+    if string is None:
+        return None
     md5 = hashlib.md5(string.encode()).hexdigest()
     return uuid.UUID(md5)
 
-- 
GitLab