Prevent Users from Changing their Profile Photo

The Doctype User has level 0 permission completely removed for the role Employee. However, a user of such role (solely Employee) can still change profile picture clicking on the user’s icon on the top right corner and chosing the option “My Profile>Edit Profile”.

Solution: Prevent Employees from Changing Profile Pictures (Server + Client Side)

The reason simple permission changes often fail is that the “My Profile” page in Frappe is a dedicated UI page, not a standard DocType Form. To block this completely, you need a two-layered approach: a Server Script for security and a Client Script for the UI.

1. The “Safety Lock” (Server Script)

This prevents any change to the user_image field in the database, even if the user tries to bypass the UI via API or Developer Tools.

  • Search for: Server Script ListAdd Server Script
  • Script Name: Prevent Employee Profile Picture Change
  • Server Script Type: DocType Event
  • Reference DocType: User
  • DocType Event: Before Save
  • Script:
# Check if the user has the 'Employee' role and is NOT a 'System Manager'
if "Employee" in [d.role for d in frappe.get_roles(doc.name)] and not "System Manager" in frappe.get_roles():
    # Fetch the existing data from the database
    old_doc = frappe.get_doc("User", doc.name)
    
    # Compare the new image with the old one
    if doc.user_image != old_doc.user_image:
        frappe.throw("Sorry, employees are not allowed to change their profile picture. Please contact HR.")


2. The “UI Mask” (Client Script)

This hides the “Edit” buttons and the camera icon to provide a better user experience, preventing users from trying to upload a photo in the first place.

  • Search for: Client Script ListAdd Client Script
  • DocType: User
  • Script:
frappe.ui.form.on('User', {
    refresh: function(frm) {
        // Standard Form: Make the image field read-only for employees
        if (frappe.user.has_role('Employee') && !frappe.user.has_role('System Manager')) {
            frm.set_df_property('user_image', 'read_only', 1);
        }
    }
});

// My Profile Page: Hide the edit buttons using jQuery
$(document).on('app_ready', function() {
    if (frappe.user.has_role('Employee') && !frappe.user.has_role('System Manager')) {
        // Use a small interval to ensure the buttons are caught when the profile modal opens
        setInterval(() => {
            $('.edit-profile-btn, .avatar-action-btn, .btn-edit-details').hide();
        }, 500);
    }
});

Why this works:

  1. Security: The Server Script is the final authority. Even if a tech-savvy user tries to send a PUT request via the API, the server will reject it.
  2. User Experience: The Client Script ensures that the “My Profile” page (which is a custom Vue/JS component) doesn’t show the editing options to unauthorized roles.

Note: After applying these scripts, remember to run Clear Cache or Reload (Ctrl+Shift+R) for the changes to take effect in the browser.