From 014f373486290b91f89878eaf22db65cf6e01154 Mon Sep 17 00:00:00 2001
From: Benjamin Bertrand <benjamin.bertrand@esss.se>
Date: Wed, 13 Dec 2017 13:53:34 +0100
Subject: [PATCH] Split main blueprint

main blueprint splitted in:
- inventory
- networks
---
 app/factory.py                                |  6 +-
 app/{main => inventory}/__init__.py           |  0
 app/inventory/forms.py                        | 40 ++++++++
 app/{main => inventory}/views.py              | 93 +++----------------
 app/networks/__init__.py                      |  0
 app/{main => networks}/forms.py               | 32 +------
 app/networks/views.py                         | 86 +++++++++++++++++
 app/templates/_helpers.html                   |  2 +-
 app/templates/admin/index.html                |  2 +-
 app/templates/base.html                       | 10 +-
 app/templates/{ => inventory}/attributes.html |  2 +-
 .../{ => inventory}/create_item.html          |  4 +-
 app/templates/{ => inventory}/items.html      |  4 +-
 app/templates/{ => inventory}/qrcodes.html    |  2 +-
 app/templates/{ => inventory}/view_item.html  |  6 +-
 app/templates/{ => networks}/create_host.html |  4 +-
 app/templates/{ => networks}/hosts.html       |  4 +-
 app/users/views.py                            |  2 +-
 18 files changed, 168 insertions(+), 131 deletions(-)
 rename app/{main => inventory}/__init__.py (100%)
 create mode 100644 app/inventory/forms.py
 rename app/{main => inventory}/views.py (58%)
 create mode 100644 app/networks/__init__.py
 rename app/{main => networks}/forms.py (55%)
 create mode 100644 app/networks/views.py
 rename app/templates/{ => inventory}/attributes.html (91%)
 rename app/templates/{ => inventory}/create_item.html (82%)
 rename app/templates/{ => inventory}/items.html (79%)
 rename app/templates/{ => inventory}/qrcodes.html (90%)
 rename app/templates/{ => inventory}/view_item.html (88%)
 rename app/templates/{ => networks}/create_host.html (81%)
 rename app/templates/{ => networks}/hosts.html (76%)

diff --git a/app/factory.py b/app/factory.py
index a29a72b..e337294 100644
--- a/app/factory.py
+++ b/app/factory.py
@@ -16,7 +16,8 @@ from . import settings, models
 from .extensions import db, migrate, login_manager, ldap_manager, bootstrap, admin, mail, jwt, toolbar
 from .admin.views import (AdminModelView, ItemAdmin, UserAdmin, GroupAdmin, TokenAdmin,
                           NetworkAdmin)
-from .main.views import bp as main
+from .inventory.views import bp as inventory
+from .networks.views import bp as networks
 from .users.views import bp as users
 from .api.main import bp as api
 from .defaults import defaults
@@ -108,7 +109,8 @@ def create_app(config=None):
     admin.add_view(AdminModelView(models.Mac, db.session))
     admin.add_view(AdminModelView(models.Cname, db.session))
 
-    app.register_blueprint(main)
+    app.register_blueprint(inventory)
+    app.register_blueprint(networks)
     app.register_blueprint(users)
     app.register_blueprint(api, url_prefix='/api')
 
diff --git a/app/main/__init__.py b/app/inventory/__init__.py
similarity index 100%
rename from app/main/__init__.py
rename to app/inventory/__init__.py
diff --git a/app/inventory/forms.py b/app/inventory/forms.py
new file mode 100644
index 0000000..ff89563
--- /dev/null
+++ b/app/inventory/forms.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+"""
+app.inventory.forms
+~~~~~~~~~~~~~~~~~~~
+
+This module defines the inventory blueprint forms.
+
+:copyright: (c) 2017 European Spallation Source ERIC
+:license: BSD 2-Clause, see LICENSE for more details.
+
+"""
+from flask_wtf import FlaskForm
+from wtforms import SelectField, StringField, SelectMultipleField, validators
+from .. import utils, models
+
+
+class AttributeForm(FlaskForm):
+    name = StringField('name', validators=[validators.DataRequired()])
+
+
+class ItemForm(FlaskForm):
+    ics_id = StringField('ICS id',
+                         validators=[validators.InputRequired(),
+                                     validators.Regexp(models.ICS_ID_RE)])
+    serial_number = StringField('Serial number',
+                                validators=[validators.InputRequired()])
+    manufacturer_id = SelectField('Manufacturer')
+    model_id = SelectField('Model')
+    location_id = SelectField('Location')
+    status_id = SelectField('Status')
+    parent_id = SelectField('Parent')
+    # macs = SelectMultipleField('Macs')
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.manufacturer_id.choices = utils.get_model_choices(models.Manufacturer, allow_blank=True)
+        self.model_id.choices = utils.get_model_choices(models.Model, allow_blank=True)
+        self.location_id.choices = utils.get_model_choices(models.Location, allow_blank=True)
+        self.status_id.choices = utils.get_model_choices(models.Status, allow_blank=True)
+        self.parent_id.choices = utils.get_model_choices(models.Item, allow_blank=True, attr='ics_id')
diff --git a/app/main/views.py b/app/inventory/views.py
similarity index 58%
rename from app/main/views.py
rename to app/inventory/views.py
index 7decb19..6347dd4 100644
--- a/app/main/views.py
+++ b/app/inventory/views.py
@@ -1,24 +1,24 @@
 # -*- coding: utf-8 -*-
 """
-app.main.views
-~~~~~~~~~~~~~~
+app.inventory.views
+~~~~~~~~~~~~~~~~~~~
 
-This module implements the main blueprint.
+This module implements the inventory blueprint.
 
 :copyright: (c) 2017 European Spallation Source ERIC
 :license: BSD 2-Clause, see LICENSE for more details.
 
 """
 import sqlalchemy as sa
-from flask import (Blueprint, render_template, jsonify, session,
-                   redirect, url_for, request, flash, current_app)
+from flask import (Blueprint, render_template, jsonify,
+                   redirect, url_for, flash, current_app)
 from flask_login import login_required
-from .forms import AttributeForm, HostForm, ItemForm
+from .forms import AttributeForm, ItemForm
 from ..extensions import db
 from ..decorators import login_groups_accepted
 from .. import utils, models
 
-bp = Blueprint('main', __name__)
+bp = Blueprint('inventory', __name__)
 
 
 # Declare custom error handlers for all views
@@ -66,7 +66,7 @@ def index():
 @bp.route('/items')
 @login_required
 def list_items():
-    return render_template('items.html')
+    return render_template('inventory/items.html')
 
 
 @bp.route('/items/create', methods=('GET', 'POST'))
@@ -91,15 +91,15 @@ def create_item():
             flash(f'{e}', 'error')
         else:
             flash(f'Item {item} created!', 'success')
-        return redirect(url_for('main.create_item'))
-    return render_template('create_item.html', form=form)
+        return redirect(url_for('inventory.create_item'))
+    return render_template('inventory/create_item.html', form=form)
 
 
 @bp.route('/items/view/<ics_id>')
 @login_required
 def view_item(ics_id):
     item = models.Item.query.filter_by(ics_id=ics_id).first_or_404()
-    return render_template('view_item.html', item=item.to_dict(long=True))
+    return render_template('inventory/view_item.html', item=item.to_dict(long=True))
 
 
 @bp.route('/qrcodes/<kind>')
@@ -113,7 +113,7 @@ def qrcodes(kind='Action'):
     images = [{'name': item.name,
                'data': utils.image_to_base64(item.image())}
               for item in items]
-    return render_template('qrcodes.html', kind=kind, images=images)
+    return render_template('inventory/qrcodes.html', kind=kind, images=images)
 
 
 @bp.route('/attributes/<kind>', methods=('GET', 'POST'))
@@ -131,8 +131,8 @@ def attributes(kind):
             flash(f'{form.name.data} already exists! {kind} not created.', 'error')
         else:
             flash(f'{kind} {new_model} created!', 'success')
-        return redirect(url_for('main.attributes', kind=kind))
-    return render_template('attributes.html', kind=kind, form=form)
+        return redirect(url_for('inventory.attributes', kind=kind))
+    return render_template('inventory/attributes.html', kind=kind, form=form)
 
 
 @bp.route('/_retrieve_attributes_name/<kind>')
@@ -145,68 +145,3 @@ def retrieve_attributes_name(kind):
     items = db.session.query(model).order_by(model.name)
     data = [[item.name] for item in items]
     return jsonify(data=data)
-
-
-@bp.route('/hosts')
-@login_required
-def list_hosts():
-    return render_template('hosts.html')
-
-
-@bp.route('/hosts/create', methods=('GET', 'POST'))
-@login_groups_accepted('admin', 'create')
-def create_host():
-    # Try to get the network_id from the session
-    # to pre-fill the form with the same network
-    try:
-        network_id = session['network_id']
-    except KeyError:
-        # No need to pass request.form when no extra keywords are given
-        form = HostForm()
-    else:
-        form = HostForm(request.form, network_id=network_id)
-    if form.validate_on_submit():
-        network_id = form.network_id.data
-        host = models.Host(ip=form.ip.data,
-                           network_id=form.network_id.data,
-                           name=form.name.data,
-                           description=form.description.data or None,
-                           mac_id=form.mac_id.data or None)
-        current_app.logger.debug(f'Trying to create: {host!r}')
-        db.session.add(host)
-        try:
-            db.session.commit()
-        except sa.exc.IntegrityError as e:
-            db.session.rollback()
-            current_app.logger.warning(f'{e}')
-            flash(f'{e}', 'error')
-        else:
-            flash(f'Host {host} created!', 'success')
-        # Save network_id to the session to retrieve it after the redirect
-        session['network_id'] = host.network_id
-        return redirect(url_for('main.create_host'))
-    return render_template('create_host.html', form=form)
-
-
-@bp.route('/_retrieve_hosts')
-@login_required
-def retrieve_hosts():
-    data = [(host.name,
-             host.ip,
-             host.description,
-             str(host.mac),
-             host.network.vlan_name) for host in models.Host.query.all()]
-    return jsonify(data=data)
-
-
-@bp.route('/_retrieve_available_ips/<network_id>')
-@login_required
-def retrieve_available_ips(network_id):
-    try:
-        network = models.Network.query.get(network_id)
-    except sa.exc.DataError:
-        current_app.logger.warning(f'Invalid network_id: {network_id}')
-        data = []
-    else:
-        data = [str(address) for address in network.available_ips()]
-    return jsonify(data=data)
diff --git a/app/networks/__init__.py b/app/networks/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/main/forms.py b/app/networks/forms.py
similarity index 55%
rename from app/main/forms.py
rename to app/networks/forms.py
index 2b3e20b..0cbba4b 100644
--- a/app/main/forms.py
+++ b/app/networks/forms.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 """
-app.main.forms
-~~~~~~~~~~~~~~
+app.networks.forms
+~~~~~~~~~~~~~~~~~~
 
-This module defines the main forms.
+This module defines the networks blueprint forms.
 
 :copyright: (c) 2017 European Spallation Source ERIC
 :license: BSD 2-Clause, see LICENSE for more details.
@@ -26,32 +26,6 @@ class NoValidateSelectField(SelectField):
         pass
 
 
-class AttributeForm(FlaskForm):
-    name = StringField('name', validators=[validators.DataRequired()])
-
-
-class ItemForm(FlaskForm):
-    ics_id = StringField('ICS id',
-                         validators=[validators.InputRequired(),
-                                     validators.Regexp(models.ICS_ID_RE)])
-    serial_number = StringField('Serial number',
-                                validators=[validators.InputRequired()])
-    manufacturer_id = SelectField('Manufacturer')
-    model_id = SelectField('Model')
-    location_id = SelectField('Location')
-    status_id = SelectField('Status')
-    parent_id = SelectField('Parent')
-    # macs = SelectMultipleField('Macs')
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.manufacturer_id.choices = utils.get_model_choices(models.Manufacturer, allow_blank=True)
-        self.model_id.choices = utils.get_model_choices(models.Model, allow_blank=True)
-        self.location_id.choices = utils.get_model_choices(models.Location, allow_blank=True)
-        self.status_id.choices = utils.get_model_choices(models.Status, allow_blank=True)
-        self.parent_id.choices = utils.get_model_choices(models.Item, allow_blank=True, attr='ics_id')
-
-
 class HostForm(FlaskForm):
     network_id = SelectField('Network')
     # The list of IPs is dynamically created on the browser side
diff --git a/app/networks/views.py b/app/networks/views.py
new file mode 100644
index 0000000..e0fd3b3
--- /dev/null
+++ b/app/networks/views.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+"""
+app.networks.views
+~~~~~~~~~~~~~~~~~~
+
+This module implements the networks blueprint.
+
+:copyright: (c) 2017 European Spallation Source ERIC
+:license: BSD 2-Clause, see LICENSE for more details.
+
+"""
+import sqlalchemy as sa
+from flask import (Blueprint, render_template, jsonify, session,
+                   redirect, url_for, request, flash, current_app)
+from flask_login import login_required
+from .forms import HostForm
+from ..extensions import db
+from ..decorators import login_groups_accepted
+from .. import models
+
+bp = Blueprint('networks', __name__)
+
+
+@bp.route('/hosts')
+@login_required
+def list_hosts():
+    return render_template('networks/hosts.html')
+
+
+@bp.route('/hosts/create', methods=('GET', 'POST'))
+@login_groups_accepted('admin', 'create')
+def create_host():
+    # Try to get the network_id from the session
+    # to pre-fill the form with the same network
+    try:
+        network_id = session['network_id']
+    except KeyError:
+        # No need to pass request.form when no extra keywords are given
+        form = HostForm()
+    else:
+        form = HostForm(request.form, network_id=network_id)
+    if form.validate_on_submit():
+        network_id = form.network_id.data
+        host = models.Host(ip=form.ip.data,
+                           network_id=form.network_id.data,
+                           name=form.name.data,
+                           description=form.description.data or None,
+                           mac_id=form.mac_id.data or None)
+        current_app.logger.debug(f'Trying to create: {host!r}')
+        db.session.add(host)
+        try:
+            db.session.commit()
+        except sa.exc.IntegrityError as e:
+            db.session.rollback()
+            current_app.logger.warning(f'{e}')
+            flash(f'{e}', 'error')
+        else:
+            flash(f'Host {host} created!', 'success')
+        # Save network_id to the session to retrieve it after the redirect
+        session['network_id'] = host.network_id
+        return redirect(url_for('networks.create_host'))
+    return render_template('networks/create_host.html', form=form)
+
+
+@bp.route('/_retrieve_hosts')
+@login_required
+def retrieve_hosts():
+    data = [(host.name,
+             host.ip,
+             host.description,
+             str(host.mac),
+             host.network.vlan_name) for host in models.Host.query.all()]
+    return jsonify(data=data)
+
+
+@bp.route('/_retrieve_available_ips/<network_id>')
+@login_required
+def retrieve_available_ips(network_id):
+    try:
+        network = models.Network.query.get(network_id)
+    except sa.exc.DataError:
+        current_app.logger.warning(f'Invalid network_id: {network_id}')
+        data = []
+    else:
+        data = [str(address) for address in network.available_ips()]
+    return jsonify(data=data)
diff --git a/app/templates/_helpers.html b/app/templates/_helpers.html
index 22aff7a..d8c2352 100644
--- a/app/templates/_helpers.html
+++ b/app/templates/_helpers.html
@@ -4,7 +4,7 @@
 
 {% macro link_to_item(ics_id) -%}
   {% if ics_id %}
-    <a href="{{ url_for('main.view_item', ics_id=ics_id) }}">{{ ics_id }}</a>
+    <a href="{{ url_for('inventory.view_item', ics_id=ics_id) }}">{{ ics_id }}</a>
   {% else %}
     {{ ics_id }}
   {% endif %}
diff --git a/app/templates/admin/index.html b/app/templates/admin/index.html
index 996ac40..03782d6 100644
--- a/app/templates/admin/index.html
+++ b/app/templates/admin/index.html
@@ -6,5 +6,5 @@
 <h2>Use the admin interface with care</h2>
 
 <!-- flask-admin uses bootstrap 3 -->
-<a class="btn btn-primary" href="{{ url_for('main.index') }}">CSEntry</a>
+<a class="btn btn-primary" href="{{ url_for('inventory.index') }}">CSEntry</a>
 {% endblock %}
diff --git a/app/templates/base.html b/app/templates/base.html
index b05c1e3..038fc7b 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -14,7 +14,7 @@
 {% block navbar %}
   <!-- Fixed navbar -->
   <div class="navbar fixed-top navbar-expand-lg navbar-light bg-light" role="navigation">
-      <a class="navbar-brand" href="{{ url_for('main.index') }}">CSEntry</a>
+      <a class="navbar-brand" href="{{ url_for('inventory.index') }}">CSEntry</a>
       <button class="navbar-toggler" type="button" data-toggle="collapse"
               data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
               aria-expanded="false" aria-label="Toggle navigation">
@@ -24,10 +24,10 @@
       <div class="collapse navbar-collapse" id="navbarSupportedContent">
         <div class="navbar-nav mr-auto">
           {% set path = request.path %}
-          <a class="nav-item nav-link {{ is_active(path.startswith("/items")) }}" href="{{ url_for('main.list_items') }}">Items</a>
-          <a class="nav-item nav-link {{ is_active(path.startswith("/hosts")) }}" href="{{ url_for('main.list_hosts') }}">Hosts</a>
-          <a class="nav-item nav-link {{ is_active(path.startswith("/attributes")) }}" href="{{ url_for('main.attributes', kind='Manufacturer') }}">Attributes</a>
-          <a class="nav-item nav-link {{ is_active(path.startswith("/qrcodes")) }}" href="{{ url_for('main.qrcodes', kind='Action') }}">QR Codes</a>
+          <a class="nav-item nav-link {{ is_active(path.startswith("/items")) }}" href="{{ url_for('inventory.list_items') }}">Items</a>
+          <a class="nav-item nav-link {{ is_active(path.startswith("/hosts")) }}" href="{{ url_for('networks.list_hosts') }}">Hosts</a>
+          <a class="nav-item nav-link {{ is_active(path.startswith("/attributes")) }}" href="{{ url_for('inventory.attributes', kind='Manufacturer') }}">Attributes</a>
+          <a class="nav-item nav-link {{ is_active(path.startswith("/qrcodes")) }}" href="{{ url_for('inventory.qrcodes', kind='Action') }}">QR Codes</a>
           {% if current_user.is_authenticated and current_user.is_admin %}
             <a class="nav-item nav-link" href="{{ url_for('admin.index') }}">Admin</a>
           {% endif %}
diff --git a/app/templates/attributes.html b/app/templates/inventory/attributes.html
similarity index 91%
rename from app/templates/attributes.html
rename to app/templates/inventory/attributes.html
index 362191e..cfff079 100644
--- a/app/templates/attributes.html
+++ b/app/templates/inventory/attributes.html
@@ -7,7 +7,7 @@
   <ul class="nav nav-tabs">
     {% for attribute in ('Manufacturer', 'Model', 'Location') %}
     <li class="nav-item">
-      <a class="nav-link {% if attribute == kind %}active{% endif %}" href="{{ url_for('main.attributes', kind=attribute) }}">{{ attribute }}</a>
+      <a class="nav-link {% if attribute == kind %}active{% endif %}" href="{{ url_for('inventory.attributes', kind=attribute) }}">{{ attribute }}</a>
     </li>
     {% endfor %}
   </ul>
diff --git a/app/templates/create_item.html b/app/templates/inventory/create_item.html
similarity index 82%
rename from app/templates/create_item.html
rename to app/templates/inventory/create_item.html
index d9b2931..3f0bfe0 100644
--- a/app/templates/create_item.html
+++ b/app/templates/inventory/create_item.html
@@ -6,10 +6,10 @@
 {% block main %}
   <ul class="nav nav-tabs">
     <li class="nav-item">
-      <a class="nav-link" href="{{ url_for('main.list_items') }}">List items</a>
+      <a class="nav-link" href="{{ url_for('inventory.list_items') }}">List items</a>
     </li>
     <li class="nav-item">
-      <a class="nav-link active" href="{{ url_for('main.create_item') }}">Register new item</a>
+      <a class="nav-link active" href="{{ url_for('inventory.create_item') }}">Register new item</a>
     </li>
   </ul>
 
diff --git a/app/templates/items.html b/app/templates/inventory/items.html
similarity index 79%
rename from app/templates/items.html
rename to app/templates/inventory/items.html
index 9576fc1..43df6de 100644
--- a/app/templates/items.html
+++ b/app/templates/inventory/items.html
@@ -5,10 +5,10 @@
 {% block main %}
   <ul class="nav nav-tabs">
     <li class="nav-item">
-      <a class="nav-link active" href="{{ url_for('main.list_items') }}">List items</a>
+      <a class="nav-link active" href="{{ url_for('inventory.list_items') }}">List items</a>
     </li>
     <li class="nav-item">
-      <a class="nav-link" href="{{ url_for('main.create_item') }}">Register new item</a>
+      <a class="nav-link" href="{{ url_for('inventory.create_item') }}">Register new item</a>
     </li>
   </ul>
 
diff --git a/app/templates/qrcodes.html b/app/templates/inventory/qrcodes.html
similarity index 90%
rename from app/templates/qrcodes.html
rename to app/templates/inventory/qrcodes.html
index d725bf4..eca4e46 100644
--- a/app/templates/qrcodes.html
+++ b/app/templates/inventory/qrcodes.html
@@ -6,7 +6,7 @@
   <ul class="nav nav-tabs">
     {% for item in ('Action', 'Manufacturer', 'Model', 'Location', 'Status') %}
     <li class="nav-item">
-      <a class="nav-link {% if kind == item %}active{% endif %}" href="{{ url_for('main.qrcodes', kind=item) }}">{{ item }}</a>
+      <a class="nav-link {% if kind == item %}active{% endif %}" href="{{ url_for('inventory.qrcodes', kind=item) }}">{{ item }}</a>
     </li>
     {% endfor %}
   </ul>
diff --git a/app/templates/view_item.html b/app/templates/inventory/view_item.html
similarity index 88%
rename from app/templates/view_item.html
rename to app/templates/inventory/view_item.html
index 27e75dc..c30766c 100644
--- a/app/templates/view_item.html
+++ b/app/templates/inventory/view_item.html
@@ -6,13 +6,13 @@
 {% block main %}
   <ul class="nav nav-tabs">
     <li class="nav-item">
-      <a class="nav-link" href="{{ url_for('main.list_items') }}">List items</a>
+      <a class="nav-link" href="{{ url_for('inventory.list_items') }}">List items</a>
     </li>
     <li class="nav-item">
-      <a class="nav-link" href="{{ url_for('main.create_item') }}">Register new item</a>
+      <a class="nav-link" href="{{ url_for('inventory.create_item') }}">Register new item</a>
     </li>
     <li class="nav-item">
-      <a class="nav-link active" href="{{ url_for('main.view_item', ics_id=item['ics_id']) }}">View item</a>
+      <a class="nav-link active" href="{{ url_for('inventory.view_item', ics_id=item['ics_id']) }}">View item</a>
     </li>
   </ul>
 
diff --git a/app/templates/create_host.html b/app/templates/networks/create_host.html
similarity index 81%
rename from app/templates/create_host.html
rename to app/templates/networks/create_host.html
index ad7c973..6c4f8f9 100644
--- a/app/templates/create_host.html
+++ b/app/templates/networks/create_host.html
@@ -6,10 +6,10 @@
 {% block main %}
   <ul class="nav nav-tabs">
     <li class="nav-item">
-      <a class="nav-link" href="{{ url_for('main.list_hosts') }}">List hosts</a>
+      <a class="nav-link" href="{{ url_for('networks.list_hosts') }}">List hosts</a>
     </li>
     <li class="nav-item">
-      <a class="nav-link active" href="{{ url_for('main.create_host') }}">Register new host</a>
+      <a class="nav-link active" href="{{ url_for('networks.create_host') }}">Register new host</a>
     </li>
   </ul>
 
diff --git a/app/templates/hosts.html b/app/templates/networks/hosts.html
similarity index 76%
rename from app/templates/hosts.html
rename to app/templates/networks/hosts.html
index 344106c..0d0f266 100644
--- a/app/templates/hosts.html
+++ b/app/templates/networks/hosts.html
@@ -5,10 +5,10 @@
 {% block main %}
   <ul class="nav nav-tabs">
     <li class="nav-item">
-      <a class="nav-link active" href="{{ url_for('main.list_hosts') }}">List hosts</a>
+      <a class="nav-link active" href="{{ url_for('networks.list_hosts') }}">List hosts</a>
     </li>
     <li class="nav-item">
-      <a class="nav-link" href="{{ url_for('main.create_host') }}">Register new host</a>
+      <a class="nav-link" href="{{ url_for('networks.create_host') }}">Register new host</a>
     </li>
   </ul>
 
diff --git a/app/users/views.py b/app/users/views.py
index ea37c5e..cc23f31 100644
--- a/app/users/views.py
+++ b/app/users/views.py
@@ -24,7 +24,7 @@ def login():
     form = LDAPLoginForm(request.form)
     if form.validate_on_submit():
         login_user(form.user, remember=form.remember_me.data)
-        return redirect(request.args.get('next') or url_for('main.index'))
+        return redirect(request.args.get('next') or url_for('items.index'))
     return render_template('users/login.html', form=form)
 
 
-- 
GitLab