Repository: netbox-community/netbox
Pull request: Added Last Login to user/profile GUI views and the /users/user API output
<!--
    Thank you for your interest in contributing to NetBox! Please note that
    our contribution policy requires that a feature request or bug report be
    approved and assigned prior to opening a pull request. This helps avoid
    waste time and effort on a proposed change that we might not be able to
    accept.

    IF YOUR PULL REQUEST DOES NOT REFERENCE AN ISSUE WHICH HAS BEEN ASSIGNED
    TO YOU, IT WILL BE CLOSED AUTOMATICALLY.

    Please specify your assigned issue number on the line below.
-->
### Fixes: #15177 

<!--
    Please include a summary of the proposed changes below.
-->
Added `last_login` to the per-user view and the account/profile page as "Account Last Login" under "Account Created", as well as in the API output of users.

Problem statement:
Add "Last Login" to per user view and API output
### NetBox version

v3.7.2

### Feature type

Change to existing functionality

### Proposed functionality

Expose the `last_login` in the specific user view (GUI), as well as include it in the API response `api/users/users/`, just as `date_joined`.

### Use case

Ease user management/cleanup. Data is already present in the DB, just not visible via API.

### Database changes

_No response_

### External dependencies

_No response_

Hints from issue discussion:

Commit message: Added Last Login to user/profile GUI and user api output

Patch to review:
diff --git a/netbox/templates/account/profile.html b/netbox/templates/account/profile.html
index cb699072c09..40d7478922f 100644
--- a/netbox/templates/account/profile.html
+++ b/netbox/templates/account/profile.html
@@ -34,6 +34,10 @@ <h5 class="card-header">{% trans "Account Details" %}</h5>
               <th scope="row">{% trans "Account Created" %}</th>
               <td>{{ request.user.date_joined|annotated_date }}</td>
             </tr>
+            <tr>
+              <th scope="row">{% trans "Account Last Login" %}</th>
+              <td>{{ object.last_login|annotated_date }}</td>
+            </tr>
             <tr>
               <th scope="row">{% trans "Superuser" %}</th>
               <td>{% checkmark request.user.is_superuser %}</td>
diff --git a/netbox/templates/users/user.html b/netbox/templates/users/user.html
index 18c07c1ccf1..51ee49bb287 100644
--- a/netbox/templates/users/user.html
+++ b/netbox/templates/users/user.html
@@ -30,6 +30,10 @@ <h5 class="card-header">{% trans "User" %}</h5>
               <th scope="row">{% trans "Account Created" %}</th>
               <td>{{ object.date_joined|annotated_date }}</td>
             </tr>
+            <tr>
+              <th scope="row">{% trans "Account Last Login" %}</th>
+              <td>{{ object.last_login|annotated_date }}</td>
+            </tr>
             <tr>
               <th scope="row">{% trans "Active" %}</th>
               <td>{% checkmark object.is_active %}</td>
diff --git a/netbox/users/api/serializers.py b/netbox/users/api/serializers.py
index c9775e39a5e..0a397d06fc8 100644
--- a/netbox/users/api/serializers.py
+++ b/netbox/users/api/serializers.py
@@ -35,7 +35,7 @@ class Meta:
         model = get_user_model()
         fields = (
             'id', 'url', 'display', 'username', 'password', 'first_name', 'last_name', 'email', 'is_staff', 'is_active',
-            'date_joined', 'groups',
+            'date_joined', 'last_login', 'groups',
         )
         extra_kwargs = {
             'password': {'write_only': True}


Code review comments:
diff_hunk: @@ -30,6 +30,10 @@ <h5 class="card-header">{% trans "User" %}</h5>
               <th scope="row">{% trans "Account Created" %}</th>
               <td>{{ object.date_joined|annotated_date }}</td>
             </tr>
+            <tr>
+              <th scope="row">{% trans "Account Last Login" %}</th>
path: netbox/templates/users/user.html
text: @user1:
```suggestion
              <th scope="row">{% trans "Last Login" %}</th>
```

diff_hunk: @@ -34,6 +34,10 @@ <h5 class="card-header">{% trans "Account Details" %}</h5>
               <th scope="row">{% trans "Account Created" %}</th>
               <td>{{ request.user.date_joined|annotated_date }}</td>
             </tr>
+            <tr>
+              <th scope="row">{% trans "Account Last Login" %}</th>
path: netbox/templates/account/profile.html
text: @user1:
```suggestion
              <th scope="row">{% trans "Last Login" %}</th>
```

diff_hunk: @@ -34,6 +34,10 @@ <h5 class="card-header">{% trans "Account Details" %}</h5>
               <th scope="row">{% trans "Account Created" %}</th>
               <td>{{ request.user.date_joined|annotated_date }}</td>
             </tr>
+            <tr>
+              <th scope="row">{% trans "Account Last Login" %}</th>
+              <td>{{ object.last_login|annotated_date }}</td>
path: netbox/templates/account/profile.html
text: @user1:
Account views are different from most object-based views, as they deal exclusively with the current user.
```suggestion
              <td>{{ request.user.last_login|annotated_date }}</td>
```