Merge branch 'develop' into feature/dockerbuild
This commit is contained in:
commit
b4c0ab0d67
@ -132,6 +132,7 @@ extensions = {
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.napoleon',
|
||||
'sphinx_rtd_theme',
|
||||
'sphinx.ext.graphviz',
|
||||
'sphinx.ext.inheritance_diagram',
|
||||
@ -205,3 +206,5 @@ set_type_checking_flag = True
|
||||
typehints_fully_qualified = True
|
||||
always_document_param_types = True
|
||||
typehints_document_rtype = True
|
||||
|
||||
napoleon_attr_annotations = True
|
||||
|
@ -115,7 +115,7 @@ class ZendeskAdmin:
|
||||
user = self.admin.users.search(email).values[0]
|
||||
return user.organization.name if user.organization else None
|
||||
|
||||
def create_admin(self) -> Zenpy:
|
||||
def create_admin(self) -> None:
|
||||
"""
|
||||
Функция создает администратора, проверяя наличие вводимых данных в env.
|
||||
|
||||
@ -142,7 +142,7 @@ class ZendeskAdmin:
|
||||
raise ValueError('invalid access_controller`s login data')
|
||||
|
||||
|
||||
def update_role(user_profile: UserProfile, role: int) -> UserProfile:
|
||||
def update_role(user_profile: UserProfile, role: int) -> None:
|
||||
"""
|
||||
Функция меняет роль пользователя.
|
||||
|
||||
@ -158,7 +158,7 @@ def update_role(user_profile: UserProfile, role: int) -> UserProfile:
|
||||
zendesk.admin.users.update(user)
|
||||
|
||||
|
||||
def make_engineer(user_profile: UserProfile, who_changes: User) -> UserProfile:
|
||||
def make_engineer(user_profile: UserProfile, who_changes: User) -> None:
|
||||
"""
|
||||
Функция устанавливает пользователю роль инженера.
|
||||
|
||||
@ -168,7 +168,7 @@ def make_engineer(user_profile: UserProfile, who_changes: User) -> UserProfile:
|
||||
update_role(user_profile, ROLES['engineer'])
|
||||
|
||||
|
||||
def make_light_agent(user_profile: UserProfile, who_changes: User) -> UserProfile:
|
||||
def make_light_agent(user_profile: UserProfile, who_changes: User) -> None:
|
||||
"""
|
||||
Функция устанавливает пользователю роль легкого агента.
|
||||
|
||||
|
@ -14,7 +14,7 @@ class CustomRegistrationForm(RegistrationFormUniqueEmail):
|
||||
:type visible_fields.email: :class:`django_registration.forms.RegistrationFormUniqueEmail`
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs) -> RegistrationFormUniqueEmail:
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
for visible in self.visible_fields():
|
||||
if visible.field.widget.attrs.get('class', False):
|
||||
@ -96,12 +96,11 @@ class StatisticForm(forms.Form):
|
||||
:type range_end: :class:`django.forms.fields.DateField`
|
||||
"""
|
||||
email = forms.EmailField(
|
||||
label='Электроная почта',
|
||||
label='Электронная почта',
|
||||
widget=forms.EmailInput(
|
||||
attrs={
|
||||
'placeholder': 'example@ngenix.ru',
|
||||
'class': 'form-control',
|
||||
'style': 'background-color:#f2f2f2;'
|
||||
}
|
||||
),
|
||||
)
|
||||
|
@ -15,21 +15,27 @@
|
||||
{% else %}
|
||||
class="btn btn-secondary"
|
||||
{% endif %}
|
||||
href="{% url 'profile' %}">Профиль</a>
|
||||
href="{% url 'profile' %}">Профиль</a>
|
||||
{% if perms.main.has_control_access %}
|
||||
<a {% if control_lit %}
|
||||
class="btn btn-primary"
|
||||
{% else %}
|
||||
class="btn btn-secondary"
|
||||
{% endif %}
|
||||
href="{% url 'control' %}">Управление</a>
|
||||
href="{% url 'control' %}">Управление</a>
|
||||
<a {% if stats_lit %}
|
||||
class="btn btn-primary"
|
||||
{% else %}
|
||||
class="btn btn-secondary"
|
||||
{% endif %}
|
||||
href="{% url 'statistic' %}">Статистика</a>
|
||||
{% else %}
|
||||
<a {% if work_lit %}
|
||||
class="btn btn-primary"
|
||||
{% else %}
|
||||
class="btn btn-secondary"
|
||||
{% endif %}
|
||||
href="{% url 'work' request.user.id %}">Запрос прав</a>
|
||||
href="{% url 'work' request.user.id %}">Запрос прав</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary" href="{% url 'logout' %}">Выйти</a>
|
||||
</div>
|
||||
@ -40,13 +46,13 @@
|
||||
{% else %}
|
||||
class="btn btn-secondary"
|
||||
{% endif %}
|
||||
href="/accounts/login">Войти</a>
|
||||
href="/accounts/login">Войти</a>
|
||||
<a {% if registration_lit %}
|
||||
class="btn btn-primary"
|
||||
{% else %}
|
||||
class="btn btn-secondary"
|
||||
{% endif %}
|
||||
href="/accounts/register">Зарегистрироваться</a>
|
||||
href="/accounts/register">Зарегистрироваться</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'main/css/work.css' %}"/>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
@ -21,7 +22,7 @@
|
||||
<div class="container-md">
|
||||
|
||||
<div class="new-section">
|
||||
<p class="row page-description">Свободных Мест: {{ licences_remaining }}</p>
|
||||
<p class="row page-description" id="licences_remaining">Свободных Мест:</p>
|
||||
</div>
|
||||
|
||||
{% block form %}
|
||||
@ -37,10 +38,16 @@
|
||||
<table class="table table-dark light-table">
|
||||
|
||||
<thead>
|
||||
<th>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="form-check-input"
|
||||
id="head-checkbox"
|
||||
/>
|
||||
</th>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Checked</th>
|
||||
</thead>
|
||||
<tbody id="tbody"></tbody>
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
<div class="col-auto">
|
||||
{% for radio in form.interval%}
|
||||
{{ radio.tag }}
|
||||
<label class="btn btn-secondary text-primary bg-white" for="{{ radio.id_for_label }}">
|
||||
<label class="btn btn-outline-secondary" for="{{ radio.id_for_label }}">
|
||||
{{ radio.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
@ -39,7 +39,7 @@
|
||||
<div class="col-auto">
|
||||
{% for radio in form.display_format%}
|
||||
{{ radio.tag }}
|
||||
<label class="btn btn-secondary text-primary bg-white" for="{{ radio.id_for_label }}">
|
||||
<label class="btn btn-outline-secondary" for="{{ radio.id_for_label }}">
|
||||
{{ radio.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
@ -67,7 +67,7 @@
|
||||
</div>
|
||||
<div class="form-row text-center">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary bg-white text-primary">Посмотреть статистику</button>
|
||||
<button type="submit" class="btn btn-outline-primary">Посмотреть статистику</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -86,9 +86,9 @@
|
||||
<table class="table table-bordered text-center text-secondary mt-5" style="background-color:#f2f2f2;">
|
||||
<thead>
|
||||
<tr>
|
||||
<td scope="col">Пользователи/Даты</td>
|
||||
<td scope="col"> </td>
|
||||
{% for date in log_stats.keys %}
|
||||
<td scope="col">{{date}}</td>
|
||||
<td scope="col">{{ date | date:'d.m' }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
@ -96,7 +96,7 @@
|
||||
<tr>
|
||||
<td>{{ form.email.value }}</td>
|
||||
{% for time in log_stats.values %}
|
||||
<td>{{time}}</td>
|
||||
<td>{{ time | floatformat:2 }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -30,13 +30,17 @@ from .models import UserProfile
|
||||
|
||||
|
||||
def setup_context(profile_lit: bool = False, control_lit: bool = False, work_lit: bool = False,
|
||||
registration_lit: bool = False, login_lit: bool = False):
|
||||
registration_lit: bool = False, login_lit: bool = False, stats_lit: bool = False):
|
||||
|
||||
print(profile_lit, control_lit, work_lit, registration_lit, login_lit)
|
||||
|
||||
context = {
|
||||
'profile_lit': profile_lit,
|
||||
'control_lit': control_lit,
|
||||
'work_lit': work_lit,
|
||||
'registration_lit': registration_lit,
|
||||
'login_lit': login_lit,
|
||||
'stats_lit': stats_lit,
|
||||
}
|
||||
return context
|
||||
|
||||
@ -300,30 +304,6 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM
|
||||
make_light_agent(user, self.request.user)
|
||||
log(user, self.request.user.userprofile)
|
||||
|
||||
def get_context_data(self, **kwargs) -> dict:
|
||||
"""
|
||||
Функция формирования контента страницы администратора (с проверкой прав доступа)
|
||||
"""
|
||||
|
||||
# context = super().get_context_data(**kwargs)
|
||||
|
||||
# context['licences_remaining'] = max(0, ZENDESK_MAX_AGENTS - context['engineers'])
|
||||
# return context
|
||||
|
||||
context = setup_context(control_lit=True)
|
||||
context.update(super().get_context_data(**kwargs))
|
||||
users = get_list_or_404(
|
||||
UserProfile, role='agent')
|
||||
context['engineers'], context['light_agents'] = count_users(get_users_list())
|
||||
context.update({
|
||||
'users': users,
|
||||
'ZENDESK_ROLES': ZENDESK_ROLES,
|
||||
'engineers': context['engineers'],
|
||||
'light_agents': context['light_agents'],
|
||||
'licences_remaining': max(0, ZENDESK_MAX_AGENTS - context['engineers']),
|
||||
})
|
||||
return context # TODO: need to get profile page url
|
||||
|
||||
|
||||
class CustomLoginView(LoginView):
|
||||
"""
|
||||
@ -349,7 +329,8 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
'users': serializer.data,
|
||||
'engineers': count[0],
|
||||
'light_agents': count[1],
|
||||
"zendesk_users": self.get_zendesk_users(self.choose_users(users.values, profiles))
|
||||
'zendesk_users': self.get_zendesk_users(self.choose_users(users.values, profiles)),
|
||||
'max_agents': ZENDESK_MAX_AGENTS
|
||||
}
|
||||
return Response(res)
|
||||
|
||||
@ -386,7 +367,7 @@ def statistic_page(request: WSGIRequest) -> HttpResponse:
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return redirect('index')
|
||||
context = setup_context()
|
||||
context = setup_context(stats_lit=True)
|
||||
context.update({
|
||||
'pagename': 'страница статистики',
|
||||
'errors': list(),
|
||||
|
@ -1,15 +1,18 @@
|
||||
"use strict";
|
||||
|
||||
function head_checkbox() {
|
||||
let head_checkbox = document.getElementById("head-checkbox");
|
||||
head_checkbox.addEventListener("click", () => {
|
||||
let checkboxes = document.getElementsByName("users");
|
||||
for (let checkbox of checkboxes) checkbox.click();
|
||||
});
|
||||
}
|
||||
|
||||
// React
|
||||
class ModelUserTableRow extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<tr className={"table-dark"}>
|
||||
<td>
|
||||
<a href="#">{this.props.user.name}</a>
|
||||
</td>
|
||||
<td>{this.props.user.user.email}</td>
|
||||
<td>{this.props.user.zendesk_role}</td>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -18,6 +21,11 @@ class ModelUserTableRow extends React.Component {
|
||||
name="users"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#">{this.props.user.name}</a>
|
||||
</td>
|
||||
<td>{this.props.user.user.email}</td>
|
||||
<td>{this.props.user.zendesk_role}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
@ -38,12 +46,12 @@ class ZendeskUserTableRow extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<tr className={"table-secondary"}>
|
||||
<td></td>
|
||||
<td>
|
||||
<a href="#">{this.props.user.name}</a>
|
||||
</td>
|
||||
<td>{this.props.user.email}</td>
|
||||
<td>{this.props.user.zendesk_role}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
@ -68,9 +76,22 @@ class TableBody extends React.Component {
|
||||
engineers: 0,
|
||||
light_agents: 0,
|
||||
zendesk_users: [],
|
||||
max_agents: 3,
|
||||
};
|
||||
}
|
||||
|
||||
change_elemnts_html() {
|
||||
let elements = document.querySelectorAll(".info-quantity-value");
|
||||
let licences = document.getElementById("licences_remaining");
|
||||
elements[0].innerHTML = this.state.engineers;
|
||||
elements[1].innerHTML = this.state.light_agents;
|
||||
let max_licences = Math.max(
|
||||
this.state.max_agents - this.state.engineers,
|
||||
0
|
||||
);
|
||||
licences.innerHTML = "Свободных мест: " + max_licences;
|
||||
}
|
||||
|
||||
async get_users() {
|
||||
await axios.get("/api/users").then((response) => {
|
||||
this.setState({
|
||||
@ -78,11 +99,10 @@ class TableBody extends React.Component {
|
||||
engineers: response.data.engineers,
|
||||
light_agents: response.data.light_agents,
|
||||
zendesk_users: response.data.zendesk_users,
|
||||
max_agents: response.data.max_agents,
|
||||
});
|
||||
let elements = document.querySelectorAll(".info-quantity-value");
|
||||
elements[0].innerHTML = this.state.engineers;
|
||||
elements[1].innerHTML = this.state.light_agents;
|
||||
});
|
||||
this.change_elemnts_html();
|
||||
}
|
||||
|
||||
delete_pretext() {
|
||||
@ -111,3 +131,4 @@ class TableBody extends React.Component {
|
||||
}
|
||||
|
||||
ReactDOM.render(<TableBody />, document.getElementById("tbody"));
|
||||
head_checkbox();
|
||||
|
Loading…
x
Reference in New Issue
Block a user