2023-03-30 12:38:40 +00:00
|
|
|
{%- extends "core/base.jinja" -%}
|
2015-11-26 15:32:56 +00:00
|
|
|
|
2023-03-30 12:38:40 +00:00
|
|
|
{%- block title -%}
|
2024-07-23 22:16:31 +00:00
|
|
|
{%- trans -%}Edit user{%- endtrans -%}
|
2023-03-30 12:38:40 +00:00
|
|
|
{%- endblock -%}
|
2016-08-13 03:33:09 +00:00
|
|
|
|
2023-03-30 12:38:40 +00:00
|
|
|
{%- block additional_css -%}
|
2024-07-23 22:16:31 +00:00
|
|
|
<link rel="stylesheet" href="{{ scss('user/user_edit.scss') }}">
|
2023-03-30 12:38:40 +00:00
|
|
|
{%- endblock -%}
|
|
|
|
|
2024-08-21 09:44:11 +00:00
|
|
|
{% macro profile_picture(field_name) %}
|
|
|
|
<div class="profile-picture" x-data="camera_{{ field_name }}" >
|
|
|
|
<div class="profile-picture-display" :aria-busy="loading" :class="{ 'camera-error': is_camera_error }">
|
|
|
|
<img
|
|
|
|
x-show="!is_camera_enabled && !is_camera_error"
|
|
|
|
:src="get_picture()"
|
|
|
|
alt="{%- trans -%}Profile{%- endtrans -%}" title="{%- trans -%}Profile{%- endtrans -%}"
|
|
|
|
loading="lazy"
|
|
|
|
/>
|
|
|
|
<video
|
|
|
|
x-show="is_camera_enabled"
|
|
|
|
x-ref="video"
|
|
|
|
></video>
|
|
|
|
<i
|
|
|
|
x-show="is_camera_error"
|
|
|
|
x-cloak
|
|
|
|
class="fa fa-eye-slash"
|
|
|
|
></i>
|
|
|
|
</div>
|
|
|
|
<div class="profile-picture-buttons" x-show="can_edit_picture">
|
|
|
|
<button
|
|
|
|
x-show="can_edit_picture && !is_camera_enabled"
|
|
|
|
class="btn btn-blue"
|
|
|
|
@click.prevent="enable_camera()"
|
|
|
|
>
|
|
|
|
<i class="fa fa-camera"></i>
|
|
|
|
{% trans %}Enable camera{% endtrans %}
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
x-show="is_camera_enabled"
|
|
|
|
class="btn btn-blue"
|
|
|
|
@click.prevent="take_picture()"
|
|
|
|
>
|
|
|
|
<i class="fa fa-camera"></i>
|
|
|
|
{% trans %}Take a picture{% endtrans %}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div x-ref="form" class="profile-picture-edit">
|
|
|
|
{%- if form[field_name] -%}
|
2024-08-21 12:37:02 +00:00
|
|
|
<div>
|
|
|
|
{{ form[field_name] }}
|
2024-08-26 14:14:12 +00:00
|
|
|
<button class="btn btn-red" @click.prevent="delete_picture()"
|
|
|
|
{%- if not (user.is_root and form.instance[field_name]) -%}
|
|
|
|
:disabled="picture == null"
|
|
|
|
{%- endif -%}
|
|
|
|
x-cloak
|
|
|
|
>
|
|
|
|
{%- trans -%}Delete{%- endtrans -%}
|
|
|
|
</button>
|
2024-08-21 12:37:02 +00:00
|
|
|
</div>
|
2024-08-21 09:44:11 +00:00
|
|
|
<p>
|
|
|
|
{{ form[field_name].label }}
|
|
|
|
</p>
|
2024-08-27 15:05:37 +00:00
|
|
|
{{ form[field_name].errors }}
|
2024-08-21 09:44:11 +00:00
|
|
|
{%- else -%}
|
|
|
|
<em>{% trans %}To edit your profile picture, ask a member of the AE{% endtrans %}</em>
|
|
|
|
{%- endif -%}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
|
|
document.addEventListener("alpine:init", () => {
|
|
|
|
Alpine.data("camera_{{ field_name }}", () => ({
|
|
|
|
can_edit_picture: false,
|
|
|
|
|
|
|
|
loading: false,
|
|
|
|
is_camera_enabled: false,
|
|
|
|
is_camera_error: false,
|
|
|
|
picture: null,
|
|
|
|
video: null,
|
|
|
|
picture_form: null,
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.video = this.$refs.video;
|
|
|
|
this.picture_form = this.$refs.form.getElementsByTagName("input");
|
|
|
|
if (this.picture_form.length > 0){
|
|
|
|
this.picture_form = this.picture_form[0];
|
|
|
|
this.can_edit_picture = true;
|
2024-08-26 13:42:24 +00:00
|
|
|
|
|
|
|
{# Link the displayed element to the form input #}
|
|
|
|
this.picture_form.onchange = (event) => {
|
|
|
|
let files = event.srcElement.files;
|
|
|
|
if (files.length > 0){
|
|
|
|
this.picture = (window.URL || window.webkitURL)
|
|
|
|
.createObjectURL(event.srcElement.files[0]);
|
|
|
|
} else {
|
|
|
|
this.picture = null;
|
|
|
|
}
|
|
|
|
}
|
2024-08-21 09:44:11 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
get_picture() {
|
|
|
|
if (this.picture != null) {
|
|
|
|
return this.picture;
|
|
|
|
}
|
|
|
|
|
|
|
|
{%- if form.instance[field_name] -%}
|
|
|
|
return "{{ form.instance[field_name].get_download_url() }}"
|
|
|
|
{%- else -%}
|
|
|
|
return "{{ static('core/img/unknown.jpg') }}"
|
|
|
|
{%- endif -%}
|
|
|
|
},
|
|
|
|
|
2024-08-26 14:14:12 +00:00
|
|
|
delete_picture() {
|
|
|
|
|
|
|
|
{# Only remove currently displayed picture #}
|
|
|
|
if (this.picture != null){
|
|
|
|
let list = new DataTransfer();
|
|
|
|
this.picture_form.files = list.files;
|
|
|
|
this.picture_form.dispatchEvent(new Event("change"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
{# Remove user picture if correct rights are available #}
|
|
|
|
{%- if user.is_root and form.instance[field_name] -%}
|
|
|
|
window.open(
|
|
|
|
'{{ url(
|
|
|
|
'core:file_delete',
|
|
|
|
file_id=form.instance[field_name].id,
|
|
|
|
popup=''
|
|
|
|
) }}',
|
|
|
|
'_self');
|
|
|
|
{%- endif -%}
|
|
|
|
},
|
|
|
|
|
2024-08-21 09:44:11 +00:00
|
|
|
enable_camera() {
|
|
|
|
this.picture = null;
|
|
|
|
this.loading = true;
|
|
|
|
this.is_camera_error = false;
|
|
|
|
navigator.mediaDevices
|
|
|
|
.getUserMedia({ video: true, audio: false })
|
|
|
|
.then((stream) => {
|
|
|
|
this.loading = false;
|
|
|
|
this.is_camera_enabled = true;
|
|
|
|
this.video.srcObject = stream;
|
|
|
|
this.video.play();
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
this.is_camera_error = true;
|
|
|
|
this.loading = false;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
take_picture() {
|
|
|
|
let canvas = document.createElement("canvas")
|
|
|
|
const context = canvas.getContext("2d");
|
|
|
|
|
2024-08-21 12:37:02 +00:00
|
|
|
/* Create the image */
|
2024-08-21 13:47:53 +00:00
|
|
|
let settings = this.video.srcObject.getTracks()[0].getSettings();
|
|
|
|
canvas.width = settings.width;
|
|
|
|
canvas.height = settings.height;
|
2024-08-21 12:37:02 +00:00
|
|
|
context.drawImage(this.video, 0, 0, canvas.width, canvas.height);
|
|
|
|
|
2024-08-21 09:44:11 +00:00
|
|
|
/* Stop camera */
|
|
|
|
this.video.pause()
|
|
|
|
this.video.srcObject.getTracks().forEach((track) => {
|
2024-09-01 17:05:54 +00:00
|
|
|
if (track.readyState === 'live') {
|
2024-08-21 09:44:11 +00:00
|
|
|
track.stop();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
canvas.toBlob((blob) => {
|
|
|
|
let file = new File(
|
|
|
|
[blob],
|
2024-09-01 17:05:54 +00:00
|
|
|
"{% trans %}captured{% endtrans %}.webp",
|
|
|
|
{ type: "image/webp" },
|
2024-08-21 09:44:11 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let list = new DataTransfer();
|
|
|
|
list.items.add(file);
|
|
|
|
this.picture_form.files = list.files;
|
|
|
|
|
2024-08-26 13:42:24 +00:00
|
|
|
{# No change event is triggered, we trigger it manually #}
|
|
|
|
this.picture_form.dispatchEvent(new Event("change"));
|
|
|
|
}, "image/webp");
|
2024-08-21 09:44:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
canvas.remove();
|
|
|
|
this.is_camera_enabled = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
{% endmacro %}
|
|
|
|
|
2023-03-30 12:38:40 +00:00
|
|
|
{%- block content -%}
|
2024-07-23 22:16:31 +00:00
|
|
|
<h2 class="title">{%- trans -%}Edit user profile{%- endtrans -%}</h2>
|
|
|
|
<form action="" method="post" enctype="multipart/form-data" id="user_edit">
|
2023-03-30 12:38:40 +00:00
|
|
|
|
|
|
|
{%- csrf_token -%}
|
2016-11-09 08:13:57 +00:00
|
|
|
{{ form.non_field_errors() }}
|
2023-03-30 12:38:40 +00:00
|
|
|
|
|
|
|
{# User Pictures #}
|
|
|
|
<div class="profile-pictures">
|
2024-08-21 09:44:11 +00:00
|
|
|
|
|
|
|
{{ profile_picture("profile_pict") }}
|
|
|
|
|
|
|
|
{{ profile_picture("avatar_pict") }}
|
|
|
|
|
|
|
|
{{ profile_picture("scrub_pict") }}
|
|
|
|
|
2023-03-30 12:38:40 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{# All fields #}
|
|
|
|
<div class="profile-fields">
|
2024-07-23 22:16:31 +00:00
|
|
|
{%- for field in form -%}
|
2023-03-30 12:38:40 +00:00
|
|
|
{%-
|
|
|
|
if field.name in ["quote","profile_pict","avatar_pict","scrub_pict","is_subscriber_viewable","forum_signature"]
|
|
|
|
-%}
|
|
|
|
{%- continue -%}
|
2024-07-23 22:16:31 +00:00
|
|
|
{%- endif -%}
|
|
|
|
|
|
|
|
<div class="profile-field">
|
|
|
|
<div class="profile-field-label">{{ field.label }}</div>
|
|
|
|
<div class="profile-field-content">
|
|
|
|
{{ field }}
|
|
|
|
{%- if field.errors -%}
|
|
|
|
<div class="field-error">{{ field.errors }}</div>
|
|
|
|
{%- endif -%}
|
2023-03-30 12:38:40 +00:00
|
|
|
</div>
|
2024-07-23 22:16:31 +00:00
|
|
|
</div>
|
|
|
|
{%- endfor -%}
|
|
|
|
</div>
|
2023-03-30 12:38:40 +00:00
|
|
|
|
|
|
|
{# Textareas #}
|
2024-07-23 22:16:31 +00:00
|
|
|
<div class="profile-fields">
|
2024-08-20 22:32:07 +00:00
|
|
|
{%- for field in [form.quote, form.forum_signature] -%}
|
2024-07-23 22:16:31 +00:00
|
|
|
<div class="profile-field">
|
|
|
|
<div class="profile-field-label">{{ field.label }}</div>
|
|
|
|
<div class="profile-field-content">
|
|
|
|
{{ field }}
|
|
|
|
{%- if field.errors -%}
|
|
|
|
<div class="field-error">{{ field.errors }}</div>
|
|
|
|
{%- endif -%}
|
|
|
|
</div>
|
2023-03-30 12:38:40 +00:00
|
|
|
</div>
|
2024-07-23 22:16:31 +00:00
|
|
|
{%- endfor -%}
|
|
|
|
</div>
|
2023-03-30 12:38:40 +00:00
|
|
|
|
|
|
|
{# Checkboxes #}
|
2024-07-23 22:16:31 +00:00
|
|
|
<div class="profile-visible">
|
2024-08-20 22:32:07 +00:00
|
|
|
{{ form.is_subscriber_viewable }}
|
|
|
|
{{ form.is_subscriber_viewable.label }}
|
2024-07-23 22:16:31 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
{%- if form.instance == user -%}
|
|
|
|
<p>
|
|
|
|
<a href="{{ url('core:password_change') }}">{%- trans -%}Change my password{%- endtrans -%}</a>
|
|
|
|
</p>
|
|
|
|
{%- elif user.is_root -%}
|
|
|
|
<p>
|
|
|
|
<a href="{{ url('core:password_root_change', user_id=form.instance.id) }}">
|
|
|
|
{%- trans -%}Change user password{%- endtrans -%}
|
|
|
|
</a>
|
|
|
|
</p>
|
|
|
|
{%- endif -%}
|
2023-03-30 12:38:40 +00:00
|
|
|
|
2024-07-23 22:16:31 +00:00
|
|
|
<p>
|
|
|
|
<input type="submit" value="{%- trans -%}Update{%- endtrans -%}" />
|
|
|
|
</p>
|
2016-07-19 17:03:16 +00:00
|
|
|
</form>
|
2015-11-26 15:32:56 +00:00
|
|
|
|
2023-03-30 12:38:40 +00:00
|
|
|
<p>
|
2024-07-23 22:16:31 +00:00
|
|
|
<em>{%- trans -%}Username: {%- endtrans -%} {{ form.instance.username }}</em>
|
|
|
|
<br />
|
|
|
|
{%- if form.instance.customer -%}
|
2023-03-30 12:38:40 +00:00
|
|
|
<em>{%- trans -%}Account number: {%- endtrans -%} {{ form.instance.customer.account_id }}</em>
|
2024-07-23 22:16:31 +00:00
|
|
|
{%- endif -%}
|
2023-03-30 12:38:40 +00:00
|
|
|
</p>
|
2015-11-26 15:32:56 +00:00
|
|
|
|
2023-03-30 12:38:40 +00:00
|
|
|
{%- endblock -%}
|