mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'tweak/user-edit' into 'dev'
BugFix User permissions | Tweak Change Password/Username See merge request crafty-controller/crafty-4!643
This commit is contained in:
commit
61d37fed85
@ -18,6 +18,7 @@
|
||||
- Fix bug where a reaction loop could be created, but would be cut short by an error when the loop occurred ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/636))
|
||||
- Use controller on update user call ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/640))
|
||||
- Move `imports` to `import/upload` in bind mount to better serve users on unraid with limited vdisk storage ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/642))
|
||||
- Fix bug where everytime a page was loaded user settings would be reset #286 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/643))
|
||||
### Refactor
|
||||
- Consolidate remaining frontend functions into API V2, and remove ajax internal API ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/585))
|
||||
- Replace bleach with nh3 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/628))
|
||||
@ -34,6 +35,7 @@
|
||||
- Bump all Crafty required python dependancies, maintaining minimum 3.9 support ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/639))
|
||||
- Better optimize and refactor docker launcher sh ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/642))
|
||||
- Improve pop-up notifications with Toasts ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/641))
|
||||
- Move username and password settings to buttons on panel config ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/643))
|
||||
### Lang
|
||||
TBD
|
||||
<br><br>
|
||||
|
@ -214,14 +214,14 @@ class UsersController:
|
||||
limit_server_creation = 0
|
||||
limit_user_creation = 0
|
||||
limit_role_creation = 0
|
||||
|
||||
PermissionsCrafty.add_or_update_user(
|
||||
user_id,
|
||||
permissions_mask,
|
||||
limit_server_creation,
|
||||
limit_user_creation,
|
||||
limit_role_creation,
|
||||
)
|
||||
if user_crafty_data:
|
||||
PermissionsCrafty.add_or_update_user(
|
||||
user_id,
|
||||
permissions_mask,
|
||||
limit_server_creation,
|
||||
limit_user_creation,
|
||||
limit_role_creation,
|
||||
)
|
||||
|
||||
self.users_helper.delete_user_roles(user_id, removed_roles)
|
||||
|
||||
|
@ -4,10 +4,7 @@ import typing as t
|
||||
|
||||
from jsonschema import ValidationError, validate
|
||||
from app.classes.controllers.users_controller import UsersController
|
||||
from app.classes.models.crafty_permissions import (
|
||||
EnumPermissionsCrafty,
|
||||
PermissionsCrafty,
|
||||
)
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
from app.classes.models.roles import HelperRoles
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
@ -247,31 +244,25 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
or data["manager"] == 0
|
||||
):
|
||||
data["manager"] = None
|
||||
|
||||
crafty_perms = None
|
||||
if "permissions" in data:
|
||||
permissions: t.List[UsersController.ApiPermissionDict] = data.pop(
|
||||
"permissions"
|
||||
)
|
||||
permissions_mask = "0" * len(EnumPermissionsCrafty)
|
||||
limit_server_creation = 0
|
||||
limit_user_creation = 0
|
||||
limit_role_creation = 0
|
||||
|
||||
for permission in permissions:
|
||||
permissions_mask = self.controller.crafty_perms.set_permission(
|
||||
permissions_mask,
|
||||
EnumPermissionsCrafty.__members__[permission["name"]],
|
||||
"1" if permission["enabled"] else "0",
|
||||
)
|
||||
|
||||
PermissionsCrafty.add_or_update_user(
|
||||
user_id,
|
||||
permissions_mask,
|
||||
limit_server_creation,
|
||||
limit_user_creation,
|
||||
limit_role_creation,
|
||||
)
|
||||
|
||||
if permissions is not None:
|
||||
server_quantity = {}
|
||||
permissions_mask = list(permissions_mask)
|
||||
for permission in permissions:
|
||||
server_quantity[permission["name"]] = permission["quantity"]
|
||||
permissions_mask[
|
||||
EnumPermissionsCrafty[permission["name"]].value
|
||||
] = ("1" if permission["enabled"] else "0")
|
||||
permissions_mask = "".join(permissions_mask)
|
||||
crafty_perms = {
|
||||
"permissions_mask": permissions_mask,
|
||||
"server_quantity": server_quantity,
|
||||
}
|
||||
# TODO: make this more efficient
|
||||
if len(data) != 0:
|
||||
for key in data:
|
||||
@ -280,7 +271,11 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
if key == "password":
|
||||
value = self.helper.encode_pass(value)
|
||||
setattr(user_obj, key, value)
|
||||
self.controller.users.update_user(auth_data[4]["user_id"], data)
|
||||
self.controller.users.update_user(
|
||||
user_id,
|
||||
data,
|
||||
crafty_perms,
|
||||
)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
user["user_id"],
|
||||
|
@ -992,23 +992,28 @@
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
function sendOrder(id_string) {
|
||||
async function sendOrder(id_string) {
|
||||
const token = getCookie("_xsrf")
|
||||
|
||||
$.ajax({
|
||||
type: "PATCH",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: `/api/v2/users/@me`,
|
||||
data: JSON.stringify({
|
||||
let res = await fetch(`/api/v2/users/@me`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
server_order: id_string,
|
||||
}),
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
},
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
return
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.status,
|
||||
message: responseData.error
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
// Inits the sortable
|
||||
$("table#servers_table tbody")
|
||||
.sortable({
|
||||
|
@ -79,7 +79,7 @@
|
||||
<tbody>
|
||||
{% for user in data['users'] %}
|
||||
<tr>
|
||||
<td><i class="fas fa-user"></i> {{ user.username }}</td>
|
||||
<td><i class="fas fa-user"></i><span id="user_{{user.user_id}}">{{ user.username }}</span></td>
|
||||
<td>
|
||||
{% if user.enabled %}
|
||||
<span class="text-success">
|
||||
@ -106,7 +106,10 @@
|
||||
{% end %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
|
||||
<td><span data-translate="{{translate('userConfig', 'userName', data['lang'])}}" data-toggle="tooltip" title="{{ translate('userConfig', 'userName', data['lang'])}}" id="username_{{user.user_id}}" class="edit_user clickable" data-name="{{user.username}}" data-id="{{user.user_id}}"><i class="fa-solid fa-user"></i></span>
|
||||
<span data-translate1="{{translate('userConfig', 'password', data['lang'])}}" data-translate2="{{translate('userConfig', 'repeat', data['lang'])}}" data-toggle="tooltip" title="{{ translate('userConfig', 'password', data['lang'])}}" class="edit_password clickable" data-id="{{user.user_id}}"><i class="fa-solid fa-lock"></i></span>
|
||||
<a data-toggle="tooltip" title="{{ translate('userConfig', 'pageTitle', data['lang'])}}" href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
{% for user in data['managed_users'] %}
|
||||
@ -138,7 +141,10 @@
|
||||
{% end %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
|
||||
<td><span data-translate="{{translate('userConfig', 'userName', data['lang'])}}" data-toggle="tooltip" title="{{ translate('userConfig', 'userName', data['lang'])}}" id="username_{{user.user_id}}" class="edit_user clickable" data-name="{{user.username}}" data-id="{{user.user_id}}"><i class="fa-solid fa-user"></i></span>
|
||||
<span data-translate1="{{translate('userConfig', 'password', data['lang'])}}" data-translate2="{{translate('userConfig', 'repeat', data['lang'])}}" data-toggle="tooltip" title="{{ translate('userConfig', 'password', data['lang'])}}" class="edit_password clickable" data-id="{{user.user_id}}"><i class="fa-solid fa-lock"></i></span>
|
||||
<a data-toggle="tooltip" title="{{ translate('userConfig', 'pageTitle', data['lang'])}}" href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
@ -274,6 +280,12 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.clickable {
|
||||
color: #007bff;
|
||||
}
|
||||
.clickable:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.custom-picker {
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
@ -312,6 +324,99 @@
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
function validateForm() {
|
||||
let password0 = document.getElementById("password0").value;
|
||||
let password1 = document.getElementById("password1").value;
|
||||
if (password0 != password1) {
|
||||
$('.passwords-match').popover('show');
|
||||
$('.popover-body').click(function () {
|
||||
$('.passwords-match').popover("hide");
|
||||
});
|
||||
document.body.scrollTop = 0;
|
||||
document.documentElement.scrollTop = 0;
|
||||
$("#password0").css("outline", "1px solid red");
|
||||
$("#password1").css("outline", "1px solid red");
|
||||
return false;
|
||||
} else {
|
||||
return password1;
|
||||
}
|
||||
}
|
||||
$(".edit_password").on("click", async function(){
|
||||
const token = getCookie("_xsrf");
|
||||
let user_id = $(this).data('id');
|
||||
bootbox.confirm(`<form class="form" id='infos' action=''>\
|
||||
<div class="form-group">
|
||||
<label for="new_password">${$(this).data("translate1")}</label>
|
||||
<input class="form-control" type='password' id="password0" name='new_password' /></br>\
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">${$(this).data("translate2")}</label>
|
||||
<input class="form-control" type='password' id="password1" name='confirm_password' />\
|
||||
</div>
|
||||
</form>`, async function(result) {
|
||||
if(result){
|
||||
password = validateForm();
|
||||
if (!password){
|
||||
return;
|
||||
}
|
||||
let res = await fetch(`/api/v2/users/${user_id}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: JSON.stringify({"password": password}),
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
console.log(responseData.data)
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.status,
|
||||
message: responseData.error
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$(document).on("submit", ".bootbox form", function(e) {
|
||||
e.preventDefault();
|
||||
$(".bootbox .btn-primary").click();
|
||||
});
|
||||
|
||||
$(".edit_user").on("click", function(){
|
||||
const token = getCookie("_xsrf");
|
||||
let username = $(this).data('name');
|
||||
let user_id = $(this).data('id');
|
||||
bootbox.confirm(`<form class="form" id='infos' action=''>\
|
||||
<div class="form-group">
|
||||
<label for="username">${$(this).data("translate")}</label>
|
||||
<input class="form-control" type='text' name='username' id="username_field" value=${username} /><br/>\
|
||||
</div>
|
||||
</form>`, async function(result) {
|
||||
if(result){
|
||||
let new_username = $("#username_field").val();
|
||||
let res = await fetch(`/api/v2/users/${user_id}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: JSON.stringify({"username": new_username}),
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
$(`#user_${user_id}`).html(` ${new_username}`)
|
||||
$(`#username_${user_id}`).data('name', new_username);
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.status,
|
||||
message: responseData.error
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if (webSocket) {
|
||||
webSocket.on('move_status', function (message) {
|
||||
if (message === "done") {
|
||||
|
@ -71,6 +71,7 @@ data['lang']) }}{% end %}
|
||||
data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if data['new_user'] %}
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">{{ translate('userConfig', 'userName', data['lang'])
|
||||
}}<small class="text-muted ml-1"> - {{ translate('userConfig', 'userNameDesc', data['lang'])
|
||||
@ -98,6 +99,15 @@ data['lang']) }}{% end %}
|
||||
data-content="{{ translate('panelConfig', 'match', data['lang']) }}" ,
|
||||
data-placement="right"></span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">{{ translate('userConfig', 'userName', data['lang'])
|
||||
}}<small class="text-muted ml-1"> - {{ translate('userConfig', 'userNameDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="text" class="form-control" name="username" id="username" autocomplete="off"
|
||||
data-lpignore="true" value="{{ data['user']['username'] }}" placeholder="User Name" disabled>
|
||||
</div>
|
||||
{% end %}
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="email">{{ translate('userConfig', 'gravEmail', data['lang'])
|
||||
}}<small class="text-muted ml-1"> - {{ translate('userConfig', 'gravDesc', data['lang'])
|
||||
@ -388,18 +398,43 @@ data['lang']) }}{% end %}
|
||||
return (isNaN(value) ? value : +value);
|
||||
}
|
||||
}
|
||||
const userId = new URLSearchParams(document.location.search).get('id')
|
||||
$("#user_form").on("submit", async function (e) {
|
||||
const userId = new URLSearchParams(document.location.search).get('id');
|
||||
console.log(userId)
|
||||
e.preventDefault();
|
||||
let password = validateForm();
|
||||
if (!password){
|
||||
return;
|
||||
let password = null;
|
||||
if(!userId){
|
||||
password = validateForm();
|
||||
if (!password){
|
||||
return;
|
||||
}
|
||||
}
|
||||
const token = getCookie("_xsrf")
|
||||
|
||||
let userRes = await fetch(`/api/v2/users/@me`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
});
|
||||
let userData = await userRes.json();
|
||||
let superuser = null;
|
||||
if (userData.status === "ok") {
|
||||
superuser = userData.data["superuser"];
|
||||
edit_id = userData.data["user_id"];
|
||||
} else {
|
||||
bootbox.alert({
|
||||
title: userData.error,
|
||||
message: userData.error
|
||||
});
|
||||
}
|
||||
|
||||
let userForm = document.getElementById("user_form");
|
||||
|
||||
let disabled_flag = false;
|
||||
let roles = $('.role_check').map(function() {
|
||||
let roles = null;
|
||||
if (superuser || userId != edit_id){
|
||||
roles = $('.role_check').map(function() {
|
||||
if ($(this).attr("disabled")){
|
||||
disabled_flag = true;
|
||||
}
|
||||
@ -407,7 +442,6 @@ data['lang']) }}{% end %}
|
||||
return $(this).val();
|
||||
}
|
||||
}).get();
|
||||
|
||||
let avail_permissions = $('.perm-name').map(function() {
|
||||
return $(this).data("perm");
|
||||
}).get();
|
||||
@ -416,20 +450,26 @@ data['lang']) }}{% end %}
|
||||
for(i=0; i < avail_permissions.length; i++){
|
||||
permissions.push({"name": avail_permissions[i], "quantity": $(`#quantity_${avail_permissions[i]}`).val(), "enabled": $(`#permission_${avail_permissions[i]}`).is(':checked')})
|
||||
}
|
||||
console.log(permissions);
|
||||
|
||||
}
|
||||
let formData = new FormData(userForm);
|
||||
//Create an object from the form data entries
|
||||
let formDataObject = Object.fromEntries(formData.entries());
|
||||
if(userId){
|
||||
delete formDataObject.username
|
||||
}
|
||||
if (superuser || userId != edit_id){
|
||||
if (!disabled_flag){
|
||||
formDataObject.roles = roles;
|
||||
}
|
||||
if ($("#permissions").length){
|
||||
formDataObject.permissions = permissions;
|
||||
}
|
||||
if(typeof password === "string"){
|
||||
if(!userId){
|
||||
if(typeof password === "string"){
|
||||
formDataObject.password = password;
|
||||
}
|
||||
}
|
||||
}
|
||||
formDataObject.enabled = $("#enabled").is(":checked");
|
||||
if ($("#superuser").is(":enabled")){
|
||||
formDataObject.superuser = $("#superuser").is(":checked");
|
||||
|
@ -615,7 +615,7 @@
|
||||
"pageTitleNew": "Create User",
|
||||
"password": "New Password",
|
||||
"permName": "Permission Name",
|
||||
"repeat": "Repeat Password",
|
||||
"repeat": "Confirm Password",
|
||||
"roleName": "Role Name",
|
||||
"selectManager": "Select Manager for User",
|
||||
"super": "Super User",
|
||||
|
Loading…
Reference in New Issue
Block a user