Merge branch 'develop' into feature/dockerbuild

This commit is contained in:
Artyom Kravchenko 2021-04-19 14:46:12 +03:00
commit b4c0ab0d67
8 changed files with 73 additions and 56 deletions

View File

@ -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

View File

@ -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:
"""
Функция устанавливает пользователю роль легкого агента.

View File

@ -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;'
}
),
)

View File

@ -23,6 +23,12 @@
class="btn btn-secondary"
{% endif %}
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"

View File

@ -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>

View File

@ -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">&nbsp;</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>

View File

@ -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(),

View File

@ -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();