From 40e726c7920217dc583a6f23b9ff0d5c8e1c801e Mon Sep 17 00:00:00 2001
From: Mikael Frykholm <mikael@frykholm.com>
Date: Sun, 27 May 2018 11:53:08 +0200
Subject: [PATCH] Djangocon coding

Pull contracts and invoices from fortnox, todo is local cache
Some more flows in the auth backend. Needs cleanup.
---
 customerportal/admin.py                       | 28 ++++++-
 customerportal/models.py                      | 74 ++++++++++++++++++-
 .../templates/customerportal/landing.html     |  9 ++-
 customerportal/views.py                       | 19 ++++-
 templates/base_generic.html                   |  2 +-
 tranquillity/auth_backend.py                  | 34 ++++++---
 tranquillity/settings.py                      |  1 +
 7 files changed, 149 insertions(+), 18 deletions(-)

diff --git a/customerportal/admin.py b/customerportal/admin.py
index 8c38f3f..e2bdf16 100644
--- a/customerportal/admin.py
+++ b/customerportal/admin.py
@@ -1,3 +1,29 @@
+"""Integrate with admin module."""
+
 from django.contrib import admin
+from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
+from django.utils.translation import ugettext_lazy as _
+
+from .models import User
+
+
+@admin.register(User)
+class UserAdmin(DjangoUserAdmin):
+    """Define admin model for custom User model with no email field."""
 
-# Register your models here.
+    fieldsets = (
+        (None, {'fields': ('email', 'password')}),
+        (_('Personal info'), {'fields': ('first_name', 'last_name','fortnox_external_id')}),
+        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
+                                       'groups', 'user_permissions')}),
+        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
+    )
+    add_fieldsets = (
+        (None, {
+            'classes': ('wide',),
+            'fields': ('email', 'password1', 'password2'),
+        }),
+    )
+    list_display = ('email', 'first_name', 'last_name', 'is_staff')
+    search_fields = ('email', 'first_name', 'last_name')
+    ordering = ('email',)
diff --git a/customerportal/models.py b/customerportal/models.py
index 71a8362..9a36b9f 100644
--- a/customerportal/models.py
+++ b/customerportal/models.py
@@ -1,3 +1,75 @@
 from django.db import models
+from django.contrib.auth.models import User
+from django.contrib.auth.models import AbstractUser
+from django.contrib.auth.models import AbstractUser, BaseUserManager ## A new class is imported. ##
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class UserManager(BaseUserManager):
+    """Define a model manager for User model with no username field."""
+
+    use_in_migrations = True
+
+    def _create_user(self, email, password, **extra_fields):
+        """Create and save a User with the given email and password."""
+        if not email:
+            raise ValueError('The given email must be set')
+        email = self.normalize_email(email)
+        user = self.model(email=email, **extra_fields)
+        user.set_password(password)
+        user.save(using=self._db)
+        return user
+
+    def create_user(self, email, password=None, **extra_fields):
+        """Create and save a regular User with the given email and password."""
+        extra_fields.setdefault('is_staff', False)
+        extra_fields.setdefault('is_superuser', False)
+        return self._create_user(email, password, **extra_fields)
+
+    def create_superuser(self, email, password, **extra_fields):
+        """Create and save a SuperUser with the given email and password."""
+        extra_fields.setdefault('is_staff', True)
+        extra_fields.setdefault('is_superuser', True)
+
+        if extra_fields.get('is_staff') is not True:
+            raise ValueError('Superuser must have is_staff=True.')
+        if extra_fields.get('is_superuser') is not True:
+            raise ValueError('Superuser must have is_superuser=True.')
+
+        return self._create_user(email, password, **extra_fields)
+
+
+class User(AbstractUser):
+    username           = None
+    fortnox_external_id = models.IntegerField()
+    gpg_public_key      = models.CharField(null=True, max_length=4096)
+    ssh_public_key      = models.CharField(null=True, max_length=4096)
+    last_login          = models.DateField(null=True)
+    cos_id              = models.CharField(null=True, max_length=4096)
+    cos_contractid      = models.CharField(null=True, max_length=4096)
+    cos_anlaggningsid   = models.CharField(null=True, max_length=4096)
+    USERNAME_FIELD = 'email'
+    REQUIRED_FIELDS = ['fortnox_external_id']
+    objects = UserManager() ## This is the new line in the User model. ##
+
+class vps(models.Model):
+    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
+    uuid = models.CharField(max_length=4096)
+    
+class physical_server(models.Model):
+    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
+    rack = models.CharField(max_length=4096)
+    unit = models.IntegerField()
+
+class IP(models.Model):
+    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
+    cidr = models.CharField(max_length=4096)
+
 
-# Create your models here.
+# graph resources
+#  port on device (realtime) autodetect on description(Cust: fortnox_external_id)
+#  cpu
+#  memory
+#  disks
+#  
diff --git a/customerportal/templates/customerportal/landing.html b/customerportal/templates/customerportal/landing.html
index 7ac974b..f5f873b 100644
--- a/customerportal/templates/customerportal/landing.html
+++ b/customerportal/templates/customerportal/landing.html
@@ -3,12 +3,13 @@
 {% block content %}
     <h1>Customer data</h1>
 
-    {% if bookinstance_list %}
+    {% if contracts %}
     <ul>
+      
+      {% for invoice in invoices %} 
+      <li class="{% if not invoice.FinalPayDate %}text-danger{% endif %}">
 
-      {% for bookinst in bookinstance_list %} 
-      <li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
-        <a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }})        
+	      Invoice date:{{invoice.InvoiceDate}} Due Date:{{invoice.DueDate}} Total:{{invoice.Total}} OCR:{{invoice.OCR}}
       </li>
       {% endfor %}
     </ul>
diff --git a/customerportal/views.py b/customerportal/views.py
index 3578d6a..182086e 100644
--- a/customerportal/views.py
+++ b/customerportal/views.py
@@ -1,9 +1,24 @@
 from django.shortcuts import render
 from django.http import HttpResponse
 from django.contrib.auth.decorators import login_required
+from django.conf import settings
+try:
+    import requests
+except ModuleNotFoundError as e:
+    pass
+
 
 @login_required
 def index(request):
-
-    return render(request, 'customerportal/landing.html')
+    headers = {"Access-Token":settings.FORTNOX_ACCESS_TOKEN,
+           "Client-Secret":settings.FORTNOX_CLIENT_SECRET,
+           "Content-Type":"application/json",
+           "Accept":"application/json" }
+    res = requests.get("https://api.fortnox.se/3/contracts/", headers=headers)
+    contracts=res.json()
+    contracts = [contract for contract in contracts['Contracts'] if int(contract['CustomerNumber']) == request.user.fortnox_external_id]
+    res = requests.get("https://api.fortnox.se/3/invoices/", headers=headers)
+    invoices = res.json()
+    invoices = [invoice for invoice in invoices['Invoices'] if int(invoice['CustomerNumber']) == request.user.fortnox_external_id]
+    return render(request, 'customerportal/landing.html',context={'contracts':contracts, 'invoices':invoices})
 
diff --git a/templates/base_generic.html b/templates/base_generic.html
index 76065ac..5a88fa6 100644
--- a/templates/base_generic.html
+++ b/templates/base_generic.html
@@ -22,7 +22,7 @@
       <ul class="sidebar-nav">
           <li><a href="{% url 'index' %}">Home</a></li>
        {% if user.is_authenticated %}
-         <li>User: {{ user.get_username }}</li>
+       <li>Welcome {{ user.first_name }} {{user.last_name}}</li>
          <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
        {% else %}
          <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
diff --git a/tranquillity/auth_backend.py b/tranquillity/auth_backend.py
index e8c682a..de43992 100644
--- a/tranquillity/auth_backend.py
+++ b/tranquillity/auth_backend.py
@@ -1,11 +1,14 @@
 from django.contrib.auth import get_user_model
 from django.contrib.auth.models import User
 from django.contrib.auth.backends import ModelBackend
-import requests
+try:
+    import requests
+except ModuleNotFoundError as e:
+    pass
 from django.conf import settings
 
 class EmailBackend(ModelBackend):
-    def fetch_fortnox(self):
+    def fetch_fortnox(self, customer_id=None):
         """ Fetch all active customers from Fortnox API. Return as dict keyed on email."""
         res = None
         customers = {}
@@ -13,9 +16,14 @@ class EmailBackend(ModelBackend):
            "Client-Secret":settings.FORTNOX_CLIENT_SECRET,
            "Content-Type":"application/json",
            "Accept":"application/json" }
-
-        res = requests.get("https://api.fortnox.se/3/customers?filter=active", headers=headers)
-        for customer in res.json()['Customers']:
+        if customer_id: #We already have id, use that to update info in local db
+            res = requests.get(f"https://api.fortnox.se/3/customers/{customer_id}?filter=active", headers=headers)
+            res = res.json()
+            res['Customer'] = [res['Customer']]
+        else:
+            res = requests.get("https://api.fortnox.se/3/customers?filter=active", headers=headers)
+        
+        for customer in res['Customer']:
             customers[customer['Email']] = customer
         return customers
 
@@ -25,22 +33,30 @@ class EmailBackend(ModelBackend):
             user = UserModel.objects.get(email=username)
         except UserModel.DoesNotExist:
             customers = self.fetch_fortnox()
+          #  import pdb;pdb.set_trace()
             if username in customers:
                 if ' ' in customers[username]['Name']:
                     (fname,lname) = customers[username]['Name'].split(' ',1)
-                    user = User.objects.create_user(username=username,
-                                     email=username,
+                    user = User.objects.create_user(email=username,
                                      first_name=fname,
-                                     last_name=lname)
+                                     last_name=lname,
+                                     fortnox_external_id=int(customers[username]['CustomerNumber']))
                     return user
                 else:
                     fname = customers[username]['Name']
                     user = User.objects.create_user(username=username,
                                  email=username,
-                                 first_name=fname)
+                                 first_name=fname,
+                                 fortnox_external_id=int(customers[username]['CustomerNumber']))
                     return user
             return None
         else:
+            customer = self.fetch_fortnox(customer_id=user.fortnox_external_id)
+            if not customer:
+                user.is_active=False
+                return None
+            user.first_name = customer[user.email]['Name'] #TODO synd more data
+            user.save()
             if user.check_password(password):
                 return user
         return None
diff --git a/tranquillity/settings.py b/tranquillity/settings.py
index b01cf5a..fc78bab 100644
--- a/tranquillity/settings.py
+++ b/tranquillity/settings.py
@@ -128,3 +128,4 @@ STATIC_URL = '/static/'
 # Redirect to home URL after login (Default redirects to /accounts/profile/)
 LOGIN_REDIRECT_URL = '/'
 AUTHENTICATION_BACKENDS = ['tranquillity.auth_backend.EmailBackend']
+AUTH_USER_MODEL = 'customerportal.User'
-- 
2.39.5