micro-users 1.1.0__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.

Files changed (33) hide show
  1. {micro_users-1.1.0 → micro_users-1.2.0}/PKG-INFO +14 -1
  2. {micro_users-1.1.0 → micro_users-1.2.0}/README.md +13 -0
  3. {micro_users-1.1.0 → micro_users-1.2.0}/micro_users.egg-info/PKG-INFO +14 -1
  4. {micro_users-1.1.0 → micro_users-1.2.0}/micro_users.egg-info/SOURCES.txt +1 -1
  5. {micro_users-1.1.0 → micro_users-1.2.0}/pyproject.toml +1 -1
  6. {micro_users-1.1.0 → micro_users-1.2.0}/setup.py +1 -1
  7. {micro_users-1.1.0 → micro_users-1.2.0}/users/tables.py +6 -0
  8. {micro_users-1.1.0 → micro_users-1.2.0}/users/templates/users/manage_users.html +1 -1
  9. {micro_users-1.1.0 → micro_users-1.2.0}/users/templates/users/user_actions.html +10 -5
  10. micro_users-1.2.0/users/templates/users/user_detail.html +49 -0
  11. {micro_users-1.1.0 → micro_users-1.2.0}/users/urls.py +4 -3
  12. {micro_users-1.1.0 → micro_users-1.2.0}/users/views.py +35 -9
  13. micro_users-1.1.0/users/tests.py +0 -3
  14. {micro_users-1.1.0 → micro_users-1.2.0}/LICENSE +0 -0
  15. {micro_users-1.1.0 → micro_users-1.2.0}/MANIFEST.in +0 -0
  16. {micro_users-1.1.0 → micro_users-1.2.0}/micro_users.egg-info/dependency_links.txt +0 -0
  17. {micro_users-1.1.0 → micro_users-1.2.0}/micro_users.egg-info/requires.txt +0 -0
  18. {micro_users-1.1.0 → micro_users-1.2.0}/micro_users.egg-info/top_level.txt +0 -0
  19. {micro_users-1.1.0 → micro_users-1.2.0}/setup.cfg +0 -0
  20. {micro_users-1.1.0 → micro_users-1.2.0}/users/__init__.py +0 -0
  21. {micro_users-1.1.0 → micro_users-1.2.0}/users/admin.py +0 -0
  22. {micro_users-1.1.0 → micro_users-1.2.0}/users/apps.py +0 -0
  23. {micro_users-1.1.0 → micro_users-1.2.0}/users/filters.py +0 -0
  24. {micro_users-1.1.0 → micro_users-1.2.0}/users/forms.py +0 -0
  25. {micro_users-1.1.0 → micro_users-1.2.0}/users/migrations/0001_initial.py +0 -0
  26. {micro_users-1.1.0 → micro_users-1.2.0}/users/migrations/__init__.py +0 -0
  27. {micro_users-1.1.0 → micro_users-1.2.0}/users/models.py +0 -0
  28. {micro_users-1.1.0 → micro_users-1.2.0}/users/signals.py +0 -0
  29. {micro_users-1.1.0 → micro_users-1.2.0}/users/templates/registration/login.html +0 -0
  30. {micro_users-1.1.0 → micro_users-1.2.0}/users/templates/user_activity_log.html +0 -0
  31. {micro_users-1.1.0 → micro_users-1.2.0}/users/templates/users/profile.html +0 -0
  32. {micro_users-1.1.0 → micro_users-1.2.0}/users/templates/users/profile_edit.html +0 -0
  33. {micro_users-1.1.0 → 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.1.0
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.1.0
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
@@ -16,7 +16,6 @@ users/forms.py
16
16
  users/models.py
17
17
  users/signals.py
18
18
  users/tables.py
19
- users/tests.py
20
19
  users/urls.py
21
20
  users/views.py
22
21
  users/migrations/0001_initial.py
@@ -27,4 +26,5 @@ users/templates/users/manage_users.html
27
26
  users/templates/users/profile.html
28
27
  users/templates/users/profile_edit.html
29
28
  users/templates/users/user_actions.html
29
+ users/templates/users/user_detail.html
30
30
  users/templates/users/user_form.html
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "micro_users"
11
- version = "1.1.0"
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.1.0",
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 = `/manage/users/delete/${userId}/`; // Update form action with user ID
68
+ form.action = "{% url 'delete_user' 0 %}".replace("/0/", `/${userId}/`);
69
69
  });
70
70
  });
71
71
  </script>
@@ -9,20 +9,25 @@
9
9
  <i class="bi bi-person-lines-fill text-dark me-1 h5"> </i> عرض
10
10
  </a>
11
11
  </li> {% endcomment %}
12
+ {% if not record.is_superuser %}
12
13
  <li>
13
- <a class="dropdown-item" href="{% url 'edit_user' record.id %}" title="تعديل">
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="تعديل">
14
20
  <i class="bi bi-person-dash-fill text-dark me-1 h5"> </i> تعديل
15
21
  </a>
16
22
  </li>
17
- {% if user.is_superuser %}
18
- {% if not record.is_staff %}
23
+ {% endif %}
24
+ {% if user.is_superuser and not record.is_staff %}
19
25
  <li>
20
26
  <a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteModal"
21
- data-user-id="{{ record.id }}" data-user-name="{{ record.username }}">
27
+ data-user-id="{{ record.pk }}" data-user-name="{{ record.username }}">
22
28
  <i class="bi bi-x-octagon text-danger me-1 h5"> </i> حذف
23
29
  </a>
24
30
  </li>
25
- {% endif %}
26
31
  {% endif %}
27
32
  </ul>
28
33
  </div>
@@ -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:user_id>/', views.edit_user, name='edit_user'),
13
- path('users/delete/<int:user_id>/', views.delete_user, name='delete_user'),
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:user_id>/', views.reset_password, name="reset_password"),
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, user_id):
84
- user = get_object_or_404(User, id=user_id)
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, user_id):
105
- user = get_object_or_404(User, id=user_id)
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, user_id):
145
- user = get_object_or_404(User, id=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", user_id=user_id) # Redirect to edit user on failure
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
 
@@ -1,3 +0,0 @@
1
- from django.test import TestCase
2
-
3
- # Create your tests here.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes