Add basic admin console

Change-Id: Ib5e17d0d0952959ad3461e17da7c2d1247594548
diff --git a/TODO.md b/TODO.md
index fc0ee65..429aa11 100644
--- a/TODO.md
+++ b/TODO.md
@@ -20,6 +20,7 @@
 - DONE: ensure columns have the right properties in DB
 - DONE: send new user registration mails to admins
 - DONE: check why newbooking is allowed if ssh key deleted after it gets added the first time
+- ensure users can only modify their own bookings
 - introduce userstatus table and relationship
 - check why error flashed after the first ssh key registration
 - configure jenkins jobs for handle and delete booking
diff --git a/app/__init__.py b/app/__init__.py
index cb01b21..b46d683 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -35,6 +35,9 @@
   from app.api import bp as api_bp
   app.register_blueprint(api_bp, url_prefix='/api')
 
+  from app.admin import bp as admin_bp
+  app.register_blueprint(admin_bp, url_prefix='/admin')
+
   from app.user import bp as user_bp
   app.register_blueprint(user_bp)
 
diff --git a/app/admin/__init__.py b/app/admin/__init__.py
new file mode 100644
index 0000000..23ed694
--- /dev/null
+++ b/app/admin/__init__.py
@@ -0,0 +1,5 @@
+from flask import Blueprint
+
+bp = Blueprint('admin', __name__)
+
+from app.admin import routes
diff --git a/app/admin/decorators.py b/app/admin/decorators.py
new file mode 100644
index 0000000..93cfb17
--- /dev/null
+++ b/app/admin/decorators.py
@@ -0,0 +1,15 @@
+from functools import wraps
+from flask import flash, redirect, url_for
+from flask_login import current_user
+
+from app.models import UserRole
+
+def admin_required(func):
+  @wraps(func)
+  def decorated_function(*args, **kwargs):
+    admin_role_id = UserRole.query.filter_by(role_name='admin').first().id
+    if current_user.role_id != admin_role_id:
+      return redirect(url_for('main.index'))
+    return func(*args, **kwargs)
+
+  return decorated_function
diff --git a/app/admin/routes.py b/app/admin/routes.py
new file mode 100644
index 0000000..0309f2f
--- /dev/null
+++ b/app/admin/routes.py
@@ -0,0 +1,44 @@
+from datetime import datetime, timedelta
+
+from flask import current_app, flash, redirect, render_template, request, url_for
+from flask_login import current_user, login_user, logout_user, login_required
+from werkzeug.urls import url_parse
+
+from app import db
+from app.email import send_email, notify_admins
+from app.admin import bp
+from app.admin.decorators import admin_required
+from app.models import Booking, BookingStatus, User, UserOrganization, UserRole
+
+@bp.route('/bookings', methods=['GET', 'POST'])
+@login_required
+@admin_required
+def bookings():
+  flash('You are logged in as admin!', 'danger')
+  booking_status_id_to_text = dict()
+  for k, v in BookingStatus.query.with_entities(BookingStatus.id, BookingStatus.status_text).all():
+    booking_status_id_to_text[k] = v
+  user_id_to_name = dict()
+  for k, v in User.query.with_entities(User.id, User.email).all():
+    user_id_to_name[k] = v
+  bookings = Booking.query.order_by(Booking.created_on.desc())
+  return render_template('admin/bookings.html', title='[nolabs] | All Bookings', user=current_user,
+   bookings=bookings, user_id_to_name=user_id_to_name, booking_status_id_to_text=booking_status_id_to_text)
+
+@bp.route('/users', methods=['GET', 'POST'])
+@login_required
+@admin_required
+def users():
+  flash('You are logged in as admin!', 'danger')
+  user_id_to_name = dict()
+  for k, v in User.query.with_entities(User.id, User.email).all():
+    user_id_to_name[k] = v
+  role_id_to_name = dict()
+  for k, v in UserRole.query.with_entities(UserRole.id, UserRole.role_name).all():
+    role_id_to_name[k] = v
+  org_id_to_name = dict()
+  for k, v in UserOrganization.query.with_entities(UserOrganization.id, UserOrganization.org_name).all():
+    org_id_to_name[k] = v
+  users = User.query.order_by(User.registered_on.desc())
+  return render_template('admin/users.html', title='[nolabs] | All Users', user=current_user,
+   users=users, user_id_to_name=user_id_to_name, role_id_to_name=role_id_to_name, org_id_to_name=org_id_to_name)
diff --git a/app/templates/admin/bookings.html b/app/templates/admin/bookings.html
new file mode 100644
index 0000000..2651319
--- /dev/null
+++ b/app/templates/admin/bookings.html
@@ -0,0 +1,61 @@
+{% extends "base.html" %}
+{% block app_content %}
+  <div class="jumbotron">
+    <h3>All Bookings</h3>
+  <br/>
+<table class="table">
+  <thead>
+    <tr>
+      <th scope="col">#</th>
+      <th scope="col">User</th>
+      <th scope="col">Flavor</th>
+      <th scope="col">IP</th>
+      <th scope="col">Created On</th>
+      <th scope="col">Expires On</th>
+      <th scope="col">Status</th>
+      <th scope="col">Action</th>
+    </tr>
+  </thead>
+  <tbody>
+    {% for booking in bookings %}
+      {% set booking_status_text = booking_status_id_to_text[booking.status_id] %}
+      {% set booking_user = user_id_to_name[booking.user_id] %}
+      {% set text_color = '#808080' %}
+      {% if booking_status_text == 'new' %}
+        {% set text_color = '#808080' %}
+      {% elif booking_status_text == 'deploying' %}
+        {% set text_color = '#f4d03f' %}
+      {% elif booking_status_text == 'active' %}
+        {% set text_color = '#239b56' %}
+      {% elif booking_status_text == 'expired' %}
+        {% set text_color = '#eb984e' %}
+      {% elif booking_status_text == 'failed' %}
+        {% set text_color = '#ff0000' %}
+      {% elif booking_status_text == 'cancelled' %}
+        {% set text_color = '#cfcbcb' %}
+      {% endif -%}
+    <tr>
+      <th scope="row">{{ booking.id }}</th>
+      <td>{{ booking_user }}</td>
+      <td>{{ booking.scenario }}</td>
+      <td>{{ booking.floating_ip }}</td>
+      <td>{{ booking.created_on }}</td>
+      <td>{{ booking.expires_on }}</td>
+      <td><b><font color='{{ text_color }}'>{{ booking_status_text }}</font></b></td>
+      <td></td>
+    </tr>
+    {% endfor %}
+  </tbody>
+</table>
+<center>
+{% if prev_url %}
+  <a href="{{ prev_url }}">Newer bookings</a>&nbsp&nbsp
+{% endif %}
+{% if next_url %}
+  <a href="{{ next_url }}">Previous bookings</a>
+{% endif %}
+</center>
+</div>
+  <div class="jumbotron" style="background:white">
+  </div>
+{% endblock %}
diff --git a/app/templates/admin/users.html b/app/templates/admin/users.html
new file mode 100644
index 0000000..44f4839
--- /dev/null
+++ b/app/templates/admin/users.html
@@ -0,0 +1,47 @@
+{% extends "base.html" %}
+{% block app_content %}
+  <div class="jumbotron">
+    <h3>All Users</h3>
+  <br/>
+<table class="table">
+  <thead>
+    <tr>
+      <th scope="col">#</th>
+      <th scope="col">Email</th>
+      <th scope="col">Organization</th>
+      <th scope="col">Role</th>
+      <th scope="col">Registered On</th>
+      <th scope="col">Last Logged in</th>
+      <th scope="col">Confirmed On</th>
+      <th scope="col">Confirmed</th>
+    </tr>
+  </thead>
+  <tbody>
+    {% for user in users %}
+      {% set user_org = org_id_to_name[user.org_id] %}
+      {% set user_role = role_id_to_name[user.role_id] %}
+    <tr>
+      <th scope="row">{{ user.id }}</th>
+      <td>{{ user.email }}</td>
+      <td>{{ user_org }}</td>
+      <td>{{ user_role }}</td>
+      <td>{{ user.registered_on }}</td>
+      <td>{{ user.last_logged_in }}</td>
+      <td>{{ user.confirmed_on }}</td>
+      <td>{{ user.confirmed }}</td>
+    </tr>
+    {% endfor %}
+  </tbody>
+</table>
+<center>
+{% if prev_url %}
+  <a href="{{ prev_url }}">Newer bookings</a>&nbsp&nbsp
+{% endif %}
+{% if next_url %}
+  <a href="{{ next_url }}">Previous bookings</a>
+{% endif %}
+</center>
+</div>
+  <div class="jumbotron" style="background:white">
+  </div>
+{% endblock %}