micro-users 1.1.1__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of micro-users might be problematic. Click here for more details.
- {micro_users-1.1.1 → micro_users-1.2.0}/PKG-INFO +14 -1
- {micro_users-1.1.1 → micro_users-1.2.0}/README.md +13 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/micro_users.egg-info/PKG-INFO +14 -1
- {micro_users-1.1.1 → micro_users-1.2.0}/micro_users.egg-info/SOURCES.txt +1 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/pyproject.toml +1 -1
- {micro_users-1.1.1 → micro_users-1.2.0}/setup.py +1 -1
- {micro_users-1.1.1 → micro_users-1.2.0}/users/tables.py +6 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/users/manage_users.html +1 -1
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/users/user_actions.html +7 -2
- micro_users-1.2.0/users/templates/users/user_detail.html +49 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/urls.py +4 -3
- {micro_users-1.1.1 → micro_users-1.2.0}/users/views.py +35 -9
- {micro_users-1.1.1 → micro_users-1.2.0}/LICENSE +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/MANIFEST.in +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/micro_users.egg-info/dependency_links.txt +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/micro_users.egg-info/requires.txt +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/micro_users.egg-info/top_level.txt +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/setup.cfg +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/__init__.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/admin.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/apps.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/filters.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/forms.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/migrations/0001_initial.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/migrations/__init__.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/models.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/signals.py +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/registration/login.html +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/user_activity_log.html +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/users/profile.html +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/users/profile_edit.html +0 -0
- {micro_users-1.1.1 → micro_users-1.2.0}/users/templates/users/user_form.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: micro_users
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Arabic Django user management app with abstract user, permissions, and activity logging
|
|
5
5
|
Home-page: https://github.com/debeski/micro-users
|
|
6
6
|
Author: DeBeski
|
|
@@ -105,3 +105,16 @@ users/
|
|
|
105
105
|
├── templates/ # HTML templates
|
|
106
106
|
└── migrations/ # Database migrations
|
|
107
107
|
```
|
|
108
|
+
|
|
109
|
+
## Version History
|
|
110
|
+
|
|
111
|
+
| Version | Changes |
|
|
112
|
+
| v1.0.0 | Initial release as pip package |
|
|
113
|
+
| v1.0.1 | Fixed a couple of new issues as a pip package |
|
|
114
|
+
| v1.0.2 | Fixed the readme and building files |
|
|
115
|
+
| v1.0.3 | Still getting the hang of this pip publish thing |
|
|
116
|
+
| v1.0.4 | Honestly still messing with and trying settings and stuff out |
|
|
117
|
+
| v1.1.0 | OK, finally a working seamless micro-users app |
|
|
118
|
+
| v1.1.1 | Fixed a bug where a staff member can edit the admin details |
|
|
119
|
+
| v1.2.0 | Added User Details view with specific user activity log |
|
|
120
|
+
| v
|
|
@@ -74,3 +74,16 @@ users/
|
|
|
74
74
|
├── templates/ # HTML templates
|
|
75
75
|
└── migrations/ # Database migrations
|
|
76
76
|
```
|
|
77
|
+
|
|
78
|
+
## Version History
|
|
79
|
+
|
|
80
|
+
| Version | Changes |
|
|
81
|
+
| v1.0.0 | Initial release as pip package |
|
|
82
|
+
| v1.0.1 | Fixed a couple of new issues as a pip package |
|
|
83
|
+
| v1.0.2 | Fixed the readme and building files |
|
|
84
|
+
| v1.0.3 | Still getting the hang of this pip publish thing |
|
|
85
|
+
| v1.0.4 | Honestly still messing with and trying settings and stuff out |
|
|
86
|
+
| v1.1.0 | OK, finally a working seamless micro-users app |
|
|
87
|
+
| v1.1.1 | Fixed a bug where a staff member can edit the admin details |
|
|
88
|
+
| v1.2.0 | Added User Details view with specific user activity log |
|
|
89
|
+
| v
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: micro-users
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Arabic Django user management app with abstract user, permissions, and activity logging
|
|
5
5
|
Home-page: https://github.com/debeski/micro-users
|
|
6
6
|
Author: DeBeski
|
|
@@ -105,3 +105,16 @@ users/
|
|
|
105
105
|
├── templates/ # HTML templates
|
|
106
106
|
└── migrations/ # Database migrations
|
|
107
107
|
```
|
|
108
|
+
|
|
109
|
+
## Version History
|
|
110
|
+
|
|
111
|
+
| Version | Changes |
|
|
112
|
+
| v1.0.0 | Initial release as pip package |
|
|
113
|
+
| v1.0.1 | Fixed a couple of new issues as a pip package |
|
|
114
|
+
| v1.0.2 | Fixed the readme and building files |
|
|
115
|
+
| v1.0.3 | Still getting the hang of this pip publish thing |
|
|
116
|
+
| v1.0.4 | Honestly still messing with and trying settings and stuff out |
|
|
117
|
+
| v1.1.0 | OK, finally a working seamless micro-users app |
|
|
118
|
+
| v1.1.1 | Fixed a bug where a staff member can edit the admin details |
|
|
119
|
+
| v1.2.0 | Added User Details view with specific user activity log |
|
|
120
|
+
| v
|
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "micro_users"
|
|
11
|
-
version = "1.
|
|
11
|
+
version = "1.2.0"
|
|
12
12
|
description = "Arabic Django user management app with abstract user, permissions, and activity logging"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
requires-python = ">=3.11"
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="micro_users",
|
|
8
|
-
version="1.
|
|
8
|
+
version="1.2.0",
|
|
9
9
|
author="DeBeski",
|
|
10
10
|
author_email="debeski1@gmail.com",
|
|
11
11
|
description="Arabic django user management app with abstract user, permissions, and activity logging",
|
|
@@ -38,3 +38,9 @@ class UserActivityLogTable(tables.Table):
|
|
|
38
38
|
template_name = "django_tables2/bootstrap5.html"
|
|
39
39
|
fields = ("timestamp", "user", "user.full_name", "action", "model_name", "object_id", "number")
|
|
40
40
|
attrs = {'class': 'table table-hover align-middle'}
|
|
41
|
+
|
|
42
|
+
class UserActivityLogTableNoUser(UserActivityLogTable):
|
|
43
|
+
class Meta(UserActivityLogTable.Meta):
|
|
44
|
+
# Remove the 'user' and 'user.full_name' columns
|
|
45
|
+
exclude = ("user", "user.full_name")
|
|
46
|
+
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
|
|
66
66
|
// Update the modal content
|
|
67
67
|
document.getElementById("userName").textContent = userName;
|
|
68
|
-
form.action =
|
|
68
|
+
form.action = "{% url 'delete_user' 0 %}".replace("/0/", `/${userId}/`);
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
</script>
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
</li> {% endcomment %}
|
|
12
12
|
{% if not record.is_superuser %}
|
|
13
13
|
<li>
|
|
14
|
-
<a class="dropdown-item" href="{% url '
|
|
14
|
+
<a class="dropdown-item" href="{% url 'user_detail' record.pk %}" title="عرض">
|
|
15
|
+
<i class="bi bi-person-dash-fill text-dark me-1 h5"> </i> عرض
|
|
16
|
+
</a>
|
|
17
|
+
</li>
|
|
18
|
+
<li>
|
|
19
|
+
<a class="dropdown-item" href="{% url 'edit_user' record.pk %}" title="تعديل">
|
|
15
20
|
<i class="bi bi-person-dash-fill text-dark me-1 h5"> </i> تعديل
|
|
16
21
|
</a>
|
|
17
22
|
</li>
|
|
@@ -19,7 +24,7 @@
|
|
|
19
24
|
{% if user.is_superuser and not record.is_staff %}
|
|
20
25
|
<li>
|
|
21
26
|
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteModal"
|
|
22
|
-
data-user-id="{{ record.
|
|
27
|
+
data-user-id="{{ record.pk }}" data-user-name="{{ record.username }}">
|
|
23
28
|
<i class="bi bi-x-octagon text-danger me-1 h5"> </i> حذف
|
|
24
29
|
</a>
|
|
25
30
|
</li>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% load crispy_forms_tags %}
|
|
3
|
+
{% load django_tables2 %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="container mt-4">
|
|
7
|
+
<!-- USER INFO CARD -->
|
|
8
|
+
<div class="card mb-4 shadow-sm">
|
|
9
|
+
<div class="card-header bg-primary text-white">
|
|
10
|
+
تفاصيل المستخدم
|
|
11
|
+
</div>
|
|
12
|
+
<div class="card-body">
|
|
13
|
+
<h5>{{ detail_user.get_full_name }} ({{ detail_user.username }})</h5>
|
|
14
|
+
<p class="mb-1"><strong>البريد:</strong> {{ detail_user.email }}</p>
|
|
15
|
+
<p class="mb-1"><strong>تاريخ الإنشاء:</strong> {{ detail_user.date_joined|date:"Y-m-d" }}</p>
|
|
16
|
+
<p class="mb-1"><strong>آخر دخول:</strong> {{ detail_user.last_login|date:"Y-m-d H:i" }}</p>
|
|
17
|
+
<p class="mb-1"><strong>الصلاحيات:</strong>
|
|
18
|
+
{% if detail_user.is_superuser %}
|
|
19
|
+
مدير النظام
|
|
20
|
+
{% elif detail_user.is_staff %}
|
|
21
|
+
مستخدم اداري
|
|
22
|
+
{% else %}
|
|
23
|
+
مستخدم عادي
|
|
24
|
+
{% endif %}
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<!-- ACTIVITY LOG TABLE -->
|
|
30
|
+
<div class="card shadow-sm">
|
|
31
|
+
<div class="card-header bg-secondary text-white">
|
|
32
|
+
سجل نشاط المستخدم
|
|
33
|
+
</div>
|
|
34
|
+
<div class="card-body">
|
|
35
|
+
{% render_table table %}
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<!-- BACK BUTTON -->
|
|
40
|
+
<div class="mb-3">
|
|
41
|
+
<a href="{% url 'manage_users' %}" class="btn btn-outline-secondary">
|
|
42
|
+
<i class="bi bi-arrow-right me-2"></i> العودة إلى إدارة المستخدمين
|
|
43
|
+
</a>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
{% endblock %}
|
|
@@ -9,10 +9,11 @@ urlpatterns = [
|
|
|
9
9
|
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
|
10
10
|
path("users/", views.UserListView.as_view(), name="manage_users"),
|
|
11
11
|
path('users/create/', views.create_user, name='create_user'),
|
|
12
|
-
path('users/edit/<int:
|
|
13
|
-
path('users/delete/<int:
|
|
12
|
+
path('users/edit/<int:pk>/', views.edit_user, name='edit_user'),
|
|
13
|
+
path('users/delete/<int:pk>/', views.delete_user, name='delete_user'),
|
|
14
14
|
path("profile", views.user_profile, name="user_profile"),
|
|
15
15
|
path('profile/edit/', views.edit_profile, name='edit_profile'),
|
|
16
16
|
path("logs/", views.UserActivityLogView.as_view(), name="user_activity_log"),
|
|
17
|
-
path('reset_password/<int:
|
|
17
|
+
path('reset_password/<int:pk>/', views.reset_password, name="reset_password"),
|
|
18
|
+
path("users/<int:pk>/", views.UserDetailView.as_view(), name="user_detail"),
|
|
18
19
|
]
|
|
@@ -7,14 +7,14 @@ from django.contrib.auth.decorators import login_required, user_passes_test
|
|
|
7
7
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
|
8
8
|
from django.http import JsonResponse
|
|
9
9
|
from django.shortcuts import render, redirect, get_object_or_404
|
|
10
|
-
from django_tables2 import RequestConfig, SingleTableView
|
|
10
|
+
from django_tables2 import RequestConfig, SingleTableView, DetailView
|
|
11
11
|
from django_filters.views import FilterView
|
|
12
12
|
|
|
13
13
|
# Project imports
|
|
14
14
|
#################
|
|
15
15
|
|
|
16
16
|
from .signals import get_client_ip
|
|
17
|
-
from .tables import UserTable, UserActivityLogTable
|
|
17
|
+
from .tables import UserTable, UserActivityLogTable, UserActivityLogTableNoUser
|
|
18
18
|
from .forms import CustomUserCreationForm, CustomUserChangeForm, ArabicPasswordChangeForm, ResetPasswordForm, UserProfileEditForm
|
|
19
19
|
from .filters import UserFilter, UserActivityLogFilter
|
|
20
20
|
from .models import UserActivityLog
|
|
@@ -32,6 +32,7 @@ def is_staff(user):
|
|
|
32
32
|
def is_superuser(user):
|
|
33
33
|
return user.is_superuser
|
|
34
34
|
|
|
35
|
+
|
|
35
36
|
# Class Function for managing users
|
|
36
37
|
class UserListView(LoginRequiredMixin, UserPassesTestMixin, FilterView, SingleTableView):
|
|
37
38
|
model = User
|
|
@@ -80,8 +81,8 @@ def create_user(request):
|
|
|
80
81
|
|
|
81
82
|
# Function for editing an existing User
|
|
82
83
|
@user_passes_test(is_staff)
|
|
83
|
-
def edit_user(request,
|
|
84
|
-
user = get_object_or_404(User,
|
|
84
|
+
def edit_user(request, pk):
|
|
85
|
+
user = get_object_or_404(User, pk=pk)
|
|
85
86
|
form_reset = ResetPasswordForm(user, data=request.POST or None)
|
|
86
87
|
|
|
87
88
|
if request.method == "POST":
|
|
@@ -101,8 +102,8 @@ def edit_user(request, user_id):
|
|
|
101
102
|
|
|
102
103
|
# Function for deleting a User
|
|
103
104
|
@user_passes_test(is_superuser)
|
|
104
|
-
def delete_user(request,
|
|
105
|
-
user = get_object_or_404(User,
|
|
105
|
+
def delete_user(request, pk):
|
|
106
|
+
user = get_object_or_404(User, pk=pk)
|
|
106
107
|
if request.method == "POST":
|
|
107
108
|
user.delete()
|
|
108
109
|
UserActivityLog.objects.create(
|
|
@@ -139,10 +140,35 @@ class UserActivityLogView(LoginRequiredMixin, UserPassesTestMixin, SingleTableVi
|
|
|
139
140
|
return context
|
|
140
141
|
|
|
141
142
|
|
|
143
|
+
class UserDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView, SingleTableView):
|
|
144
|
+
model = User
|
|
145
|
+
template_name = "users/user_detail.html"
|
|
146
|
+
context_object_name = "detail_user" # Keep clear naming
|
|
147
|
+
table_class = UserActivityLogTableNoUser
|
|
148
|
+
paginate_by = 10
|
|
149
|
+
|
|
150
|
+
def test_func(self):
|
|
151
|
+
# only staff can view user detail page
|
|
152
|
+
return self.request.user.is_staff
|
|
153
|
+
|
|
154
|
+
def get_queryset(self):
|
|
155
|
+
# This is for the DetailView (only target user)
|
|
156
|
+
return User.objects.all()
|
|
157
|
+
|
|
158
|
+
def get_table_data(self):
|
|
159
|
+
# filter log table to user in URL
|
|
160
|
+
return UserActivityLog.objects.filter(user=self.get_object()).order_by('-timestamp')
|
|
161
|
+
|
|
162
|
+
def get_context_data(self, **kwargs):
|
|
163
|
+
context = super().get_context_data(**kwargs)
|
|
164
|
+
context['table'] = self.get_table() # table instance
|
|
165
|
+
return context
|
|
166
|
+
|
|
167
|
+
|
|
142
168
|
# Function that resets a user password
|
|
143
169
|
@user_passes_test(is_staff)
|
|
144
|
-
def reset_password(request,
|
|
145
|
-
user = get_object_or_404(User, id=
|
|
170
|
+
def reset_password(request, pk):
|
|
171
|
+
user = get_object_or_404(User, id=pk)
|
|
146
172
|
|
|
147
173
|
if request.method == "POST":
|
|
148
174
|
form = ResetPasswordForm(user=user, data=request.POST) # ✅ Correct usage with SetPasswordForm
|
|
@@ -151,7 +177,7 @@ def reset_password(request, user_id):
|
|
|
151
177
|
return redirect("manage_users") # Redirect after successful reset
|
|
152
178
|
else:
|
|
153
179
|
print("Form errors:", form.errors) # Debugging
|
|
154
|
-
return redirect("edit_user",
|
|
180
|
+
return redirect("edit_user", pk=pk) # Redirect to edit user on failure
|
|
155
181
|
|
|
156
182
|
return redirect("manage_users") # Fallback redirect
|
|
157
183
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|