micro-users 1.0.0__py3-none-any.whl → 1.0.2__py3-none-any.whl
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.
- {micro_users-1.0.0.dist-info → micro_users-1.0.2.dist-info}/METADATA +21 -29
- micro_users-1.0.2.dist-info/RECORD +24 -0
- users/migrations/__init__.py +0 -0
- users/static/css/login.css +134 -0
- users/templates/registration/login.html +115 -0
- users/templates/user_activity_log.html +22 -0
- users/templates/users/manage_users.html +73 -0
- users/templates/users/profile.html +63 -0
- users/templates/users/profile_edit.html +77 -0
- users/templates/users/user_actions.html +29 -0
- users/templates/users/user_form.html +37 -0
- micro_users-1.0.0.dist-info/RECORD +0 -15
- {micro_users-1.0.0.dist-info → micro_users-1.0.2.dist-info}/LICENSE +0 -0
- {micro_users-1.0.0.dist-info → micro_users-1.0.2.dist-info}/WHEEL +0 -0
- {micro_users-1.0.0.dist-info → micro_users-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: micro-users
|
|
3
|
-
Version: 1.0.
|
|
4
|
-
Summary: Django user management app with abstract user, permissions, and activity logging
|
|
3
|
+
Version: 1.0.2
|
|
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
|
|
7
7
|
Author-email: DeBeski <debeski1@gmail.com>
|
|
@@ -27,11 +27,23 @@ Requires-Dist: django-filter (>=25.1)
|
|
|
27
27
|
Requires-Dist: pillow (>=11.0)
|
|
28
28
|
Requires-Dist: babel (>=2.1)
|
|
29
29
|
|
|
30
|
-
# Micro Users - Django User Management App
|
|
30
|
+
# Micro Users - Arabic Django User Management App
|
|
31
31
|
|
|
32
32
|
[](https://pypi.org/project/micro-users/)
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
**Arabic** lightweight, reusable Django app providing user management with abstract user, permissions, localization, and activity logging.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
- **Must be installed on a fresh database.**
|
|
39
|
+
- Python 3.9+
|
|
40
|
+
- Django 5.1+
|
|
41
|
+
- django-crispy-forms 2.4+
|
|
42
|
+
- django-tables2 2.7+
|
|
43
|
+
- django-filter 24.3+
|
|
44
|
+
- pillow 11.0+
|
|
45
|
+
- babel 2.1+
|
|
46
|
+
|
|
35
47
|
|
|
36
48
|
## Features
|
|
37
49
|
- Custom AbstractUser model
|
|
@@ -55,24 +67,23 @@ pip install micro-users
|
|
|
55
67
|
1. Add to `INSTALLED_APPS`:
|
|
56
68
|
```python
|
|
57
69
|
INSTALLED_APPS = [
|
|
70
|
+
'users', # Preferably on top
|
|
71
|
+
'django.contrib.admin',
|
|
72
|
+
'django.contrib.auth',
|
|
58
73
|
...
|
|
59
|
-
'django_tables2',
|
|
60
|
-
'django_filters',
|
|
61
|
-
'crispy_forms',
|
|
62
|
-
'users', # Add this
|
|
63
74
|
]
|
|
64
75
|
```
|
|
65
76
|
|
|
66
77
|
2. Set custom user model in settings.py:
|
|
67
78
|
```python
|
|
68
|
-
AUTH_USER_MODEL = 'users.
|
|
79
|
+
AUTH_USER_MODEL = 'users.CustomUser'
|
|
69
80
|
```
|
|
70
81
|
|
|
71
82
|
3. Include URLs in your main project folder `urls.py`:
|
|
72
83
|
```python
|
|
73
84
|
urlpatterns = [
|
|
74
85
|
...
|
|
75
|
-
path('
|
|
86
|
+
path('manage/', include('users.urls')),
|
|
76
87
|
]
|
|
77
88
|
```
|
|
78
89
|
|
|
@@ -82,10 +93,6 @@ python manage.py makemigrations users
|
|
|
82
93
|
python manage.py migrate users
|
|
83
94
|
```
|
|
84
95
|
|
|
85
|
-
## Requirements
|
|
86
|
-
- Python 3.9+
|
|
87
|
-
- Django 5.1+
|
|
88
|
-
- See setup.py for full dependencies
|
|
89
96
|
|
|
90
97
|
## Structure
|
|
91
98
|
```
|
|
@@ -97,18 +104,3 @@ users/
|
|
|
97
104
|
├── templates/ # HTML templates
|
|
98
105
|
└── migrations/ # Database migrations
|
|
99
106
|
```
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## **Directory structure:**
|
|
103
|
-
```
|
|
104
|
-
micro-users/
|
|
105
|
-
├── users/ # This is the actual package name
|
|
106
|
-
│ ├── __init__.py
|
|
107
|
-
│ ├── models.py
|
|
108
|
-
│ ├── views.py
|
|
109
|
-
│ ├── urls.py
|
|
110
|
-
│ ├── admin.py
|
|
111
|
-
│ └── templates/
|
|
112
|
-
├── setup.py
|
|
113
|
-
└── README.md
|
|
114
|
-
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
users/admin.py,sha256=VF0V6hQ9Obcdinnjb8nBHaknas2p3O5w-6yAJ-DeARQ,636
|
|
3
|
+
users/apps.py,sha256=Xb1nGvCl08KaUVqcUG82-jYdG6-KTVjaw_lgr5GIuYY,1133
|
|
4
|
+
users/filters.py,sha256=9-yrWBF-CdWb1nrAhmifWb1AHI0z4LQma1uR_9jLr2U,4797
|
|
5
|
+
users/forms.py,sha256=q3kVpGKEunYXuGNSBl3h_I-Q8hdD_7nru1lx9vMGoLA,18356
|
|
6
|
+
users/models.py,sha256=KX_6LoiNJN6PCTFOuuGp5so4CNn5pAh1Vpaigv4fKk4,2060
|
|
7
|
+
users/signals.py,sha256=5Kd3KyfPT6740rvwZj4vy1yXsmjVhmaQ__RB8p5R5aE,1336
|
|
8
|
+
users/tables.py,sha256=JS3fvZvwzcNPGAH1LfCCUNnuQXgauDnB--rFt4okC0I,1717
|
|
9
|
+
users/urls.py,sha256=gmk_ZkSg9Bj-fUpIRACL_X7MEADTgZ7uvmbvXoAo5fo,956
|
|
10
|
+
users/views.py,sha256=yfzWkIDha66YK-Rgz7GH7MhQsupSCojf59C7fBqkppI,7209
|
|
11
|
+
users/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
users/static/css/login.css,sha256=SiJ6jBbWQAP2Nxt7DOTZbTcFYP9JEp557AuQZ9Eirb0,2120
|
|
13
|
+
users/templates/user_activity_log.html,sha256=S_FDN6vVLz_mB826yjeU9vtVGtzk7E_LKBmQIeYtdkQ,611
|
|
14
|
+
users/templates/registration/login.html,sha256=owbzO_XjqMeSncwWxkTzsvbkhjEZd7LdbblC3HBnld0,4091
|
|
15
|
+
users/templates/users/manage_users.html,sha256=jaYxUGRPyqx8tj9M6aApUZOgmgAIQekFtaL5j1mRPRQ,2951
|
|
16
|
+
users/templates/users/profile.html,sha256=9ahVF6YZUR-6-c8SKc0rN2pVdis2lI9gbcOQZeMaFnY,2909
|
|
17
|
+
users/templates/users/profile_edit.html,sha256=sgO3h9ffVK1vnDNl4E6l5x3xfam3FTQl6Lqkrw5gmlw,4215
|
|
18
|
+
users/templates/users/user_actions.html,sha256=33y-aFqzsFm7yMSzBFGtuT-95hhyQV8CFppU3Oev54A,1366
|
|
19
|
+
users/templates/users/user_form.html,sha256=jcyI7OQZOY4ue4DajPtfjAt2SmAYO5ZgHNOqTp2-FO0,1352
|
|
20
|
+
micro_users-1.0.2.dist-info/LICENSE,sha256=Fco89ULLSSxKkC2KKnx57SaT0R7WOkZfuk8IYcGiN50,1063
|
|
21
|
+
micro_users-1.0.2.dist-info/METADATA,sha256=2q125PFAbfTKeAu5qWlYkHwcVwZQFg3HioDrOjjor_U,2752
|
|
22
|
+
micro_users-1.0.2.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
23
|
+
micro_users-1.0.2.dist-info/top_level.txt,sha256=tWT24ZcWau2wrlbpU_h3mP2jRukyLaVYiyHBuOezpLQ,6
|
|
24
|
+
micro_users-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
::selection {
|
|
2
|
+
background: #d4c591;
|
|
3
|
+
}
|
|
4
|
+
::-webkit-selection {
|
|
5
|
+
background: #d4c591;
|
|
6
|
+
}
|
|
7
|
+
::-moz-selection {
|
|
8
|
+
background: #c9aa5e;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.page {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
height: calc(100% - 15vh);
|
|
15
|
+
position: absolute;
|
|
16
|
+
place-content: center;
|
|
17
|
+
width: calc(100% - 40px);
|
|
18
|
+
}
|
|
19
|
+
@media (max-width: 767px) {
|
|
20
|
+
.page {
|
|
21
|
+
height: auto;
|
|
22
|
+
margin-bottom: 20px;
|
|
23
|
+
padding-bottom: 20px;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
.container {
|
|
27
|
+
height: 320px;
|
|
28
|
+
margin: 0 auto;
|
|
29
|
+
width: 640px;
|
|
30
|
+
}
|
|
31
|
+
@media (max-width: 767px) {
|
|
32
|
+
.container {
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
height: 630px;
|
|
35
|
+
width: 320px;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
.left {
|
|
39
|
+
background: white;
|
|
40
|
+
height: calc(100% - 40px);
|
|
41
|
+
top: 20px;
|
|
42
|
+
position: relative;
|
|
43
|
+
width: 60%;
|
|
44
|
+
box-shadow: 0px 0px 10px 4px rgba(0,0,0,0.03);
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
@media (max-width: 767px) {
|
|
48
|
+
.left {
|
|
49
|
+
height: 100%;
|
|
50
|
+
left: 5%;
|
|
51
|
+
width: 110%;
|
|
52
|
+
max-height: 270px;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/* .login {
|
|
56
|
+
font-size: 38px;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
}
|
|
59
|
+
.eula {
|
|
60
|
+
color: #adadad;
|
|
61
|
+
font-size: 14px;
|
|
62
|
+
line-height: 1.5;
|
|
63
|
+
margin: 40px;
|
|
64
|
+
} */
|
|
65
|
+
.right {
|
|
66
|
+
background: #cb9447;
|
|
67
|
+
box-shadow: 0px 0px 20px 8px rgba(0,0,0,0.07);
|
|
68
|
+
color: #F1F1F2;
|
|
69
|
+
position: relative;
|
|
70
|
+
width: 58%;
|
|
71
|
+
}
|
|
72
|
+
@media (max-width: 767px) {
|
|
73
|
+
.right {
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
height: 100%;
|
|
76
|
+
width: 100%;
|
|
77
|
+
max-height: 350px;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
svg {
|
|
81
|
+
position: absolute;
|
|
82
|
+
width: 320px;
|
|
83
|
+
}
|
|
84
|
+
path {
|
|
85
|
+
fill: none;
|
|
86
|
+
stroke: url(#linearGradient);;
|
|
87
|
+
stroke-width: 3;
|
|
88
|
+
stroke-dasharray: 240 1386;
|
|
89
|
+
}
|
|
90
|
+
.form {
|
|
91
|
+
margin: 35px 35px 35px 20px;
|
|
92
|
+
position: absolute;
|
|
93
|
+
}
|
|
94
|
+
label {
|
|
95
|
+
color: #c2c2c5;
|
|
96
|
+
display: block;
|
|
97
|
+
font-size: 14px;
|
|
98
|
+
height: 16px;
|
|
99
|
+
margin-top: 20px;
|
|
100
|
+
margin-bottom: 5px;
|
|
101
|
+
}
|
|
102
|
+
input {
|
|
103
|
+
background: transparent;
|
|
104
|
+
border: 0;
|
|
105
|
+
color: #2d0202;
|
|
106
|
+
font-size: 20px;
|
|
107
|
+
height: 30px;
|
|
108
|
+
line-height: 30px;
|
|
109
|
+
outline: none !important;
|
|
110
|
+
width: 100%;
|
|
111
|
+
margin-top: 30px;
|
|
112
|
+
margin-bottom: 10px;
|
|
113
|
+
}
|
|
114
|
+
input::-moz-focus-inner {
|
|
115
|
+
border: 0;
|
|
116
|
+
}
|
|
117
|
+
#submit {
|
|
118
|
+
color: #707075;
|
|
119
|
+
margin-top: 40px;
|
|
120
|
+
transition: color 300ms;
|
|
121
|
+
}
|
|
122
|
+
#submit:focus {
|
|
123
|
+
color: #575757;
|
|
124
|
+
}
|
|
125
|
+
#submit:active {
|
|
126
|
+
color: #4d4d4d;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.titlebar {
|
|
130
|
+
background-color: var(--title);
|
|
131
|
+
flex-direction: row;
|
|
132
|
+
height: 7vh;
|
|
133
|
+
justify-content: center !important
|
|
134
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
{% extends 'base.html' %}
|
|
2
|
+
{% load static %}
|
|
3
|
+
{% block title %}تسجيل الدخول{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<link rel="stylesheet" href="{% static 'css/login.css' %}">
|
|
7
|
+
|
|
8
|
+
<div class="page">
|
|
9
|
+
<div class="container d-flex">
|
|
10
|
+
<div class="right p-2 d-felx align-content-center">
|
|
11
|
+
<div class="">
|
|
12
|
+
<img src="{% static 'img/pdf_logo.webp' %}" alt="Ministry Logo" class="img-fluid mx-auto d-block "style="width: 75%;">
|
|
13
|
+
</div>
|
|
14
|
+
{% comment %} <div class="login mb-3 text-secondary">تسجيل الدخــول</div> {% endcomment %}
|
|
15
|
+
</div>
|
|
16
|
+
<div class="left">
|
|
17
|
+
<svg viewBox="0 0 320 300">
|
|
18
|
+
<defs>
|
|
19
|
+
<linearGradient
|
|
20
|
+
inkscape:collect="always"
|
|
21
|
+
id="linearGradient"
|
|
22
|
+
x1="13"
|
|
23
|
+
y1="193.49992"
|
|
24
|
+
x2="307"
|
|
25
|
+
y2="193.49992"
|
|
26
|
+
gradientUnits="userSpaceOnUse">
|
|
27
|
+
<stop
|
|
28
|
+
style="stop-color:#c9aa5e;"
|
|
29
|
+
offset="0"
|
|
30
|
+
id="stop876" />
|
|
31
|
+
<stop
|
|
32
|
+
style="stop-color:#cb9447;"
|
|
33
|
+
offset="1"
|
|
34
|
+
id="stop878" />
|
|
35
|
+
</linearGradient>
|
|
36
|
+
</defs>
|
|
37
|
+
<path d="m 40,120.00016 239.99984,-3.2e-4 c 0,0 24.99263,0.79932 25.00016,35.00016 0.008,34.20084 -25.00016,35 -25.00016,35 h -239.99984 c 0,-0.0205 -25,4.01348 -25,38.5 0,34.48652 25,38.5 25,38.5 h 215 c 0,0 20,-0.99604 20,-25 0,-24.00396 -20,-25 -20,-25 h -190 c 0,0 -20,1.71033 -20,25 0,24.00396 20,25 20,25 h 168.57143" />
|
|
38
|
+
</svg>
|
|
39
|
+
<form action="{% url 'login' %}" method="POST">
|
|
40
|
+
{% csrf_token %}
|
|
41
|
+
<div class="form">
|
|
42
|
+
<input type="text" style="font-size: 28px;" id="username" name="username" autofocus placeholder="اسم المستخدم" required>
|
|
43
|
+
|
|
44
|
+
<input type="password" style="font-size: 28px;" id="password" name="password" placeholder="كلمة المرور" required>
|
|
45
|
+
|
|
46
|
+
<input type="submit" style="font-size: 25px;" class="mt-5 pe-3" value="دخول" id="submit">
|
|
47
|
+
</div>
|
|
48
|
+
</form>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<script nonce="{{ request.csp_nonce }}">
|
|
54
|
+
var current = null;
|
|
55
|
+
document.querySelector('#username').addEventListener('focus', function(e) {
|
|
56
|
+
if (current) current.pause();
|
|
57
|
+
current = anime({
|
|
58
|
+
targets: 'path',
|
|
59
|
+
strokeDashoffset: {
|
|
60
|
+
value: 0,
|
|
61
|
+
duration: 700,
|
|
62
|
+
easing: 'easeOutQuart'
|
|
63
|
+
},
|
|
64
|
+
strokeDasharray: {
|
|
65
|
+
value: '240 1386',
|
|
66
|
+
duration: 700,
|
|
67
|
+
easing: 'easeOutQuart'
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
document.querySelector('#password').addEventListener('focus', function(e) {
|
|
72
|
+
if (current) current.pause();
|
|
73
|
+
current = anime({
|
|
74
|
+
targets: 'path',
|
|
75
|
+
strokeDashoffset: {
|
|
76
|
+
value: -336,
|
|
77
|
+
duration: 700,
|
|
78
|
+
easing: 'easeOutQuart'
|
|
79
|
+
},
|
|
80
|
+
strokeDasharray: {
|
|
81
|
+
value: '240 1386',
|
|
82
|
+
duration: 700,
|
|
83
|
+
easing: 'easeOutQuart'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
document.querySelector('#submit').addEventListener('focus', function(e) {
|
|
88
|
+
if (current) current.pause();
|
|
89
|
+
current = anime({
|
|
90
|
+
targets: 'path',
|
|
91
|
+
strokeDashoffset: {
|
|
92
|
+
value: -730,
|
|
93
|
+
duration: 700,
|
|
94
|
+
easing: 'easeOutQuart'
|
|
95
|
+
},
|
|
96
|
+
strokeDasharray: {
|
|
97
|
+
value: '530 1386',
|
|
98
|
+
duration: 700,
|
|
99
|
+
easing: 'easeOutQuart'
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// New script: Hide the login button in the title bar if present.
|
|
105
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
106
|
+
// Adjust the selector to match the login button in your title bar.
|
|
107
|
+
var loginTitleButton = document.querySelector(".login-title-btn");
|
|
108
|
+
if (loginTitleButton) {
|
|
109
|
+
loginTitleButton.style.display = "none";
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<script src="{% static 'js/anime.min.js' %}"></script>
|
|
115
|
+
{% endblock %}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% load django_tables2 %}
|
|
3
|
+
{% load crispy_forms_tags %}
|
|
4
|
+
{% block title %}الاعدادت - السجل{% endblock %}
|
|
5
|
+
|
|
6
|
+
{% block content %}
|
|
7
|
+
|
|
8
|
+
<form method="get" class="py-3 row g-2 no-print m-0">
|
|
9
|
+
{% crispy filter.form %}
|
|
10
|
+
</form>
|
|
11
|
+
|
|
12
|
+
<div class="card border-light shadow">
|
|
13
|
+
<!-- <div class="card-header text-center pe-5 text-bg-warning">
|
|
14
|
+
<h3 class="card-title">السجل</h3>
|
|
15
|
+
</div> -->
|
|
16
|
+
<div class="card-body p-0 table-responsive">
|
|
17
|
+
<!-- Render the table -->
|
|
18
|
+
{% render_table table %}
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
{% endblock %}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% load django_tables2 %}
|
|
3
|
+
{% load crispy_forms_tags %}
|
|
4
|
+
|
|
5
|
+
{% block title %}الاعدادت - إدارة المستخدمين{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block content %}
|
|
8
|
+
|
|
9
|
+
<form method="get" class="mb-3">
|
|
10
|
+
{% crispy filter.form %}
|
|
11
|
+
</form>
|
|
12
|
+
|
|
13
|
+
<div class="card border-light shadow">
|
|
14
|
+
<!-- <div class="card-header text-center pe-5 text-bg-warning">
|
|
15
|
+
<h3 class="card-title">إدارة المستخدمين</h3>
|
|
16
|
+
</div> -->
|
|
17
|
+
<div class="card-body p-0 table-responsive-lg">
|
|
18
|
+
<!-- Render the table -->
|
|
19
|
+
{% render_table table %}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="mt-3">
|
|
24
|
+
<a href="{% url 'create_user' %}" class="btn btn-success" title="إضافة مستخدم جديد">
|
|
25
|
+
<i class="bi bi-person-plus-fill text-light me-1 h4"></i> إضافة مستخدم جديد
|
|
26
|
+
</a>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<!-- Delete Modal -->
|
|
30
|
+
{% if request.user.is_superuser %}
|
|
31
|
+
<form id="deleteForm" method="post">
|
|
32
|
+
{% csrf_token %}
|
|
33
|
+
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
|
34
|
+
<div class="modal-dialog">
|
|
35
|
+
<div class="modal-content">
|
|
36
|
+
<div class="modal-header">
|
|
37
|
+
<h5 class="modal-title" id="deleteModalLabel">تأكيد الحذف</h5>
|
|
38
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="modal-body">
|
|
41
|
+
<p>هل انت متأكد انك تريد حذف العضو <strong><span id="userName"></span></strong>؟</p>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="modal-footer">
|
|
44
|
+
<button type="submit" class="btn btn-danger">نعم، احذف</button>
|
|
45
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</form>
|
|
51
|
+
{% endif %}
|
|
52
|
+
|
|
53
|
+
{% endblock %}
|
|
54
|
+
|
|
55
|
+
{% block scripts %}
|
|
56
|
+
|
|
57
|
+
<script nonce="{{ request.csp_nonce }}">
|
|
58
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
59
|
+
const deleteModal = document.getElementById("deleteModal");
|
|
60
|
+
deleteModal.addEventListener("show.bs.modal", function (event) {
|
|
61
|
+
let button = event.relatedTarget; // Button that triggered the modal
|
|
62
|
+
let userId = button.getAttribute("data-user-id");
|
|
63
|
+
let userName = button.getAttribute("data-user-name");
|
|
64
|
+
let form = document.getElementById("deleteForm");
|
|
65
|
+
|
|
66
|
+
// Update the modal content
|
|
67
|
+
document.getElementById("userName").textContent = userName;
|
|
68
|
+
form.action = `/manage/users/delete/${userId}/`; // Update form action with user ID
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
{% endblock %}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% load django_tables2 %}
|
|
3
|
+
{% load crispy_forms_tags %}
|
|
4
|
+
{% load static %}
|
|
5
|
+
|
|
6
|
+
{% block title %}الملف الشخصي{% endblock %}
|
|
7
|
+
|
|
8
|
+
{% block content %}
|
|
9
|
+
|
|
10
|
+
<div class="card">
|
|
11
|
+
<div class="card-header display-5">
|
|
12
|
+
<h1><strong>الــملف الشخصــي</strong></h1>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="card-body row">
|
|
15
|
+
<div class="mt-4 col-md-9 h2">
|
|
16
|
+
<p><strong>اسم الـمستخدم:</strong> {{ user.username }}</p>
|
|
17
|
+
<p><strong>البريد الالكتروني:</strong> {{ user.email }}</p>
|
|
18
|
+
<p><strong>الاســــــــــــــــــم:</strong> {{ user.full_name }}</p>
|
|
19
|
+
<p><strong>رقـــــم الـــهاتف:</strong> {{ user.phone }}</p>
|
|
20
|
+
<p><strong>جهـــــة الـــعمل:</strong> {{ user.occupation }}</p>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="col-md-3 mt-4 d-block mx-auto">
|
|
23
|
+
<img src="{% static 'img/default_profile.webp' %}" alt="Profile Image" class="img-thumbnail" width="250">
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="row mt-4">
|
|
28
|
+
<form method="post">
|
|
29
|
+
{% csrf_token %}
|
|
30
|
+
<a class="btn btn-success" href="{% url 'edit_profile' %}" role="button" title="تحديث البيانات">
|
|
31
|
+
<i class="bi bi-pencil-square text-light me-1 h4"></i> تحديث البيانات
|
|
32
|
+
</a>
|
|
33
|
+
|
|
34
|
+
<a class="btn btn-danger" href="#" role="button" data-bs-toggle="modal" data-bs-target="#resetPasswordModal" title="تغيير كلمة المرور">
|
|
35
|
+
<i class="bi bi-lock text-light me-1 h4"></i> تغيير كلمة المرور
|
|
36
|
+
</a>
|
|
37
|
+
|
|
38
|
+
<a href="{% url 'index' %}" class="btn btn-dark" title="الرئيسية">
|
|
39
|
+
<i class="bi bi-house-door text-light me-1 h4"></i> الرئيسية
|
|
40
|
+
</a>
|
|
41
|
+
</form>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<!-- Change Password Modal -->
|
|
45
|
+
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
|
46
|
+
<div class="modal-dialog">
|
|
47
|
+
<div class="modal-content">
|
|
48
|
+
<div class="modal-header">
|
|
49
|
+
<h5 class="modal-title" id="resetPasswordModalLabel">تغيير كلمة المرور</h5>
|
|
50
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="modal-body">
|
|
53
|
+
<form method="post">
|
|
54
|
+
{% csrf_token %}
|
|
55
|
+
{{ password_form|crispy }}
|
|
56
|
+
<button type="submit" name="change_password" class="btn btn-success">تـغـيــيــر</button>
|
|
57
|
+
</form>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
{% endblock %}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% load django_tables2 %}
|
|
3
|
+
{% load crispy_forms_tags %}
|
|
4
|
+
{% load static %}
|
|
5
|
+
|
|
6
|
+
{% block title %}تحديث الملف الشخصي{% endblock %}
|
|
7
|
+
|
|
8
|
+
{% block content %}
|
|
9
|
+
|
|
10
|
+
<form method="POST" enctype="multipart/form-data">
|
|
11
|
+
{% csrf_token %}
|
|
12
|
+
<div class="card">
|
|
13
|
+
<div class="card-header display-5">
|
|
14
|
+
<h1><strong>تحديث الملف الشخصي</strong></h1>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="card-body row">
|
|
17
|
+
<div class="mt-4 col-md-9 h2">
|
|
18
|
+
<div class="mb-3 d-flex align-items-center">
|
|
19
|
+
<p class="m-0 me-2" style="white-space: nowrap;"><strong>اسم الـمستخدم: </strong></p>
|
|
20
|
+
<input type="text" name="username" id="username" class="form-control" value="{{ user.username }}">
|
|
21
|
+
</div>
|
|
22
|
+
<div class="mb-3 d-flex align-items-center">
|
|
23
|
+
<p class="m-0 me-2" style="white-space: nowrap;"><strong>البريد الالكتروني: </strong></p>
|
|
24
|
+
<input type="email" name="email" id="email" class="form-control" value="{{ user.email }}">
|
|
25
|
+
</div>
|
|
26
|
+
<div class="mb-3 d-flex align-items-center">
|
|
27
|
+
<p class="m-0 me-2" style="white-space: nowrap;"><strong>الاســــــــــــــــــم: </strong></p>
|
|
28
|
+
<input type="text" name="first_name" id="first_name" class="form-control" value="{{ user.first_name }}">
|
|
29
|
+
<p class="m-0 me-2" style="white-space: nowrap;"><strong>الـــلقب: </strong></p>
|
|
30
|
+
<input type="text" name="last_name" id="last_name" class="form-control" value="{{ user.last_name }}">
|
|
31
|
+
</div>
|
|
32
|
+
<div class="mb-3 d-flex align-items-center">
|
|
33
|
+
<p class="m-0 me-2" style="white-space: nowrap;"><strong>رقـــــم الـــهاتف: </strong></p>
|
|
34
|
+
<input type="text" name="phone" id="phone" class="form-control" value="{{ user.phone }}">
|
|
35
|
+
</div>
|
|
36
|
+
<div class="mb-3 d-flex align-items-center">
|
|
37
|
+
<p class="m-0 me-2" style="white-space: nowrap;"><strong>جهـــــة الـــعمل: </strong></p>
|
|
38
|
+
<input type="text" name="occupation" id="occupation" class="form-control" value="{{ user.occupation }}">
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="col-md-3 mt-4 d-block mx-auto">
|
|
42
|
+
<img id="profile_image_preview"
|
|
43
|
+
src="{% static 'img/default_profile.webp' %}"
|
|
44
|
+
alt="Profile Image" class="img-thumbnail" width="250">
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="mt-4">
|
|
49
|
+
<button type="submit" class="btn btn-success" title="حفظ التغييرات">
|
|
50
|
+
<i class="bi bi-check2-square text-light me-1 h4"></i> حفظ التغييرات
|
|
51
|
+
</button>
|
|
52
|
+
<a href="{% url 'user_profile' %}" class="btn btn-danger" title="إلغـــاء">
|
|
53
|
+
<i class="bi bi-x-circle text-light me-1 h4"></i> إلغـــاء
|
|
54
|
+
</a>
|
|
55
|
+
</div>
|
|
56
|
+
</form>
|
|
57
|
+
|
|
58
|
+
<!-- Change Password Modal -->
|
|
59
|
+
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
|
60
|
+
<div class="modal-dialog">
|
|
61
|
+
<div class="modal-content">
|
|
62
|
+
<div class="modal-header">
|
|
63
|
+
<h5 class="modal-title" id="resetPasswordModalLabel">تغيير كلمة المرور</h5>
|
|
64
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="modal-body">
|
|
67
|
+
<form method="post">
|
|
68
|
+
{% csrf_token %}
|
|
69
|
+
{{ password_form.as_p }}
|
|
70
|
+
<button type="submit" name="change_password" class="btn btn-success">تغيير</button>
|
|
71
|
+
</form>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
{% endblock %}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<div class="d-flex gap-2 align-items-center justify-content-end no-print">
|
|
2
|
+
<div class="dropdown-center">
|
|
3
|
+
<a href="#" class="action-icon" id="actionDropdown{{ record.id }}" data-bs-toggle="dropdown" aria-expanded="false">
|
|
4
|
+
<i class="bi bi-three-dots-vertical text-dark"></i>
|
|
5
|
+
</a>
|
|
6
|
+
<ul class="dropdown-menu" aria-labelledby="actionDropdown{{ record.id }}">
|
|
7
|
+
{% comment %} <li>
|
|
8
|
+
<a class="dropdown-item" href="#" title="عرض">
|
|
9
|
+
<i class="bi bi-person-lines-fill text-dark me-1 h5"> </i> عرض
|
|
10
|
+
</a>
|
|
11
|
+
</li> {% endcomment %}
|
|
12
|
+
<li>
|
|
13
|
+
<a class="dropdown-item" href="{% url 'edit_user' record.id %}" title="تعديل">
|
|
14
|
+
<i class="bi bi-person-dash-fill text-dark me-1 h5"> </i> تعديل
|
|
15
|
+
</a>
|
|
16
|
+
</li>
|
|
17
|
+
{% if user.is_superuser %}
|
|
18
|
+
{% if not record.is_staff %}
|
|
19
|
+
<li>
|
|
20
|
+
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteModal"
|
|
21
|
+
data-user-id="{{ record.id }}" data-user-name="{{ record.username }}">
|
|
22
|
+
<i class="bi bi-x-octagon text-danger me-1 h5"> </i> حذف
|
|
23
|
+
</a>
|
|
24
|
+
</li>
|
|
25
|
+
{% endif %}
|
|
26
|
+
{% endif %}
|
|
27
|
+
</ul>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
{% load crispy_forms_tags %}
|
|
3
|
+
|
|
4
|
+
{% block title %}{% if edit_mode %}تعديل{% else %}إضافة{% endif %} مستخدم{% endblock %}
|
|
5
|
+
|
|
6
|
+
{% block content %}
|
|
7
|
+
<div class="container mt-4">
|
|
8
|
+
<h2>{% if edit_mode %}تعديل{% else %}إضافة{% endif %} مستخدم</h2>
|
|
9
|
+
|
|
10
|
+
<form method="post" class="mt-3">
|
|
11
|
+
{% csrf_token %}
|
|
12
|
+
{% crispy form %}
|
|
13
|
+
</form>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<!-- Modal for Password Reset -->
|
|
17
|
+
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
|
18
|
+
<div class="modal-dialog">
|
|
19
|
+
<div class="modal-content">
|
|
20
|
+
<div class="modal-header">
|
|
21
|
+
<h5 class="modal-title" id="resetPasswordModalLabel">إعادة تعيين كلمة المرور</h5>
|
|
22
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="modal-body">
|
|
25
|
+
{% if form_reset %}
|
|
26
|
+
<form method="post" action="{% url 'reset_password' form_reset.user.id %}">
|
|
27
|
+
{% csrf_token %}
|
|
28
|
+
{% crispy form_reset %}
|
|
29
|
+
<!-- Display the password hash (optional) -->
|
|
30
|
+
</form>
|
|
31
|
+
{% endif %}
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
{% endblock %}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
users/admin.py,sha256=VF0V6hQ9Obcdinnjb8nBHaknas2p3O5w-6yAJ-DeARQ,636
|
|
3
|
-
users/apps.py,sha256=Xb1nGvCl08KaUVqcUG82-jYdG6-KTVjaw_lgr5GIuYY,1133
|
|
4
|
-
users/filters.py,sha256=9-yrWBF-CdWb1nrAhmifWb1AHI0z4LQma1uR_9jLr2U,4797
|
|
5
|
-
users/forms.py,sha256=q3kVpGKEunYXuGNSBl3h_I-Q8hdD_7nru1lx9vMGoLA,18356
|
|
6
|
-
users/models.py,sha256=KX_6LoiNJN6PCTFOuuGp5so4CNn5pAh1Vpaigv4fKk4,2060
|
|
7
|
-
users/signals.py,sha256=5Kd3KyfPT6740rvwZj4vy1yXsmjVhmaQ__RB8p5R5aE,1336
|
|
8
|
-
users/tables.py,sha256=JS3fvZvwzcNPGAH1LfCCUNnuQXgauDnB--rFt4okC0I,1717
|
|
9
|
-
users/urls.py,sha256=gmk_ZkSg9Bj-fUpIRACL_X7MEADTgZ7uvmbvXoAo5fo,956
|
|
10
|
-
users/views.py,sha256=yfzWkIDha66YK-Rgz7GH7MhQsupSCojf59C7fBqkppI,7209
|
|
11
|
-
micro_users-1.0.0.dist-info/LICENSE,sha256=Fco89ULLSSxKkC2KKnx57SaT0R7WOkZfuk8IYcGiN50,1063
|
|
12
|
-
micro_users-1.0.0.dist-info/METADATA,sha256=NUdccS9etYjBfjthrCZ48Dz1Vp-x0irUmnCFycIPRWs,2921
|
|
13
|
-
micro_users-1.0.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
14
|
-
micro_users-1.0.0.dist-info/top_level.txt,sha256=tWT24ZcWau2wrlbpU_h3mP2jRukyLaVYiyHBuOezpLQ,6
|
|
15
|
-
micro_users-1.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|