Developer forum

Forum » Templates » Get Users from same group

Get Users from same group

Bjørn Kamfjord
Reply

So, I'm looking for some tips for how to set up some functionality. What I want to achieve is this.

When a "Department Manager" from one of my Customers shops on my site, she finds a product that she want to buy for some of her employees. So when she opens the product, there should be a list of her employees as a drop down above the size variants. She picks an employee, "Peter Parker" and gets his size preference predefined to small.  (if there is a preference). Add to cart, with a comment like "For: Peter Parker". She then picks "Tony Stark" and have his size prefrences ready and add to cart, repeat for all the relevant employees.

To create this we are thinking of Creating users in backend with custom-fields for size prefrences.

We'll sort them into groups for each Company and department like this:

Company-1 (Group)
|--Department-1 (Sub-Group)
|----User-1 (Department-Admin)(User)
|----User-2
|----User-3
|--Department-2
|----User-4
|----User-5
|----User-6
|--User-10 (Company-Admin)

Company-2
|--Department-1
|---User-A
.....

If I do it like this, is there a way for a User to list out his/hers "sibling" users? So User-1 will se User-2 and User-3 but not User-4,5,6 etc. ?

I off course need to have som sort administration of this as well....

Is there another aproach to solve this?

Replies

 
Nicolai Pedersen
Nicolai Pedersen
Reply

Hi Bjørn

I think you can do this. On a department admin user, you can take that user object, look at the users groups properties and find all users in there. That can be done from the product template if written in Razor. The size information is then easy to map to a variant.

You can get the current logged in user using User.Current: https://doc.dynamicweb.com/api/html/25aa3b0f-43c4-65ea-948c-131abd318626.htm

And locate the group:

https://doc.dynamicweb.com/api/html/9247917b-9eb6-1cd4-ea5b-9653bfc333f4.htm

So something like

var user = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser();
var group = user.Groups[0]; //Expection exactly one group - not 0 not 2 or more
var users = group.Users;
foreach(var u in users)
{
        var name = u.Name;
}

When adding the product to the cart, you can if you want, get one line for each person by having a custom orderline field for the name and fille that out when adding the product to the cart.

 
Bjørn Kamfjord
Reply

To update. If someone else needs something similar. Heres my code...

@{
                        var user = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser();
                        var group = user.Groups[0]; //Expection exactly one group - not 0 not 2 or more
                        var users = group.Users;
                        var groupParent = group.Parent;
                        string sizeType = GetString("Ecom:Product:Field.SizeType");
                    }
                    @if (groupParent != null)
                    {
                        <p>Hei @user.Name, du kan bestille til ansatte i @group.Name</p>

                        if (group.Parent.Name.Contains("Storkunder"))
                        {
                        <select class="js-employee custom-select">
                            <option></option>
                            @foreach (var sg in group.Subgroups)
                            {
                                <optgroup label="@sg.Name" />
                                foreach (var u in sg.Users)
                                {
                                    var cfValues = u.CustomFieldValues;
                                    var size = string.Empty;
                                    foreach (var cf in cfValues)
                                    {
                                        if (cf.CustomField.Name.Contains(sizeType))
                                        {
                                            size = cf.Value.ToString();
                                        }
                                    }
                                    <option data-size-type="@sizeType" data-employee-name="@u.Name" value="@size">
                                        @u.Name
                                    </option>
                                }
                            }
                        </select>
                        }
                    
                        else if (group.Parent.Parent.Name.Contains("Storkunder"))
                        {
                            <select class="js-employee custom-select">
                                <option></option>
                                @foreach (var u in users)
                                {
                                    var cfValues = u.CustomFieldValues;
                                    <option data-size-type="@sizeType" data-employee-name="@u.Name" value='@foreach (var cf in cfValues)
                                    {
                                        if (cf.CustomField.Name.Contains(sizeType))
                                        {
                                            @cf.Value
                                        }
                                    }'>
                                        @u.Name
                                    </option>  
                                }
                            </select>
                        }
                    }
                    
                    <hr class="divider_type_3 m_bottom_15">

                    @*Variants start*@

                    @*Variant select*@
                    @if (variantCount > 0)
                    {
                        foreach (LoopItem vg in GetLoop("VariantGroups"))
                        {
                    <label class="variant-select-label f_left m-2">@vg.GetString("Ecom:VariantGroup.Name")</label>
                            List<LoopItem> variantOptions = vg.GetLoop("VariantAvailableOptions");
                            {
                                <select id="@vg.GetString("Ecom:VariantGroup.ID")" @((variantOptions.Count > 1) ? string.Empty : "style='display:none;'") class="custom-select js-variant-select @((vg.GetString("Ecom:VariantGroup.ID") == "VARGRP6") ? "js-variant-size" : string.Empty)">
                                
                                    @foreach (LoopItem vao in variantOptions.OrderBy(t => int.TryParse(t.GetString("Ecom:VariantOption.Name"), out sizeArray) ? sizeArray : t.GetInteger("Ecom:VariantOption.SortOrder")))
                                    {
                                        <option @(vao.GetBoolean("Ecom:VariantOption.Selected") ? "selected" : string.Empty) value="@vao.GetString("Ecom:VariantOption.ID")">@vao.GetString("Ecom:VariantOption.Name")</option>
                                    }
                                </select>
                            }
                        }

                        @*Variants prices *@
                        foreach (LoopItem i in GetLoop("VariantCombinations"))
                        {
                            <div class="js-variant-price m_top_10 " id='@i.GetValue("Ecom:VariantCombination.VariantID")'>
                                @if (allowBuy)
                                {
                                <form method="post" role="form">
                                    <input type="hidden" name="ID" value="@GetValue("Ecom:Product:Page.ID")" />
                                    <input type="hidden" name="ProductID" value="@GetValue("Ecom:Product.ID")" />
                                    <input type="hidden" name="VariantID" value="@i.GetValue("Ecom:VariantCombination.VariantID")" />
                                    <input type="hidden" name="EcomOrderLineFieldInput_EmployeeName" size="100"  value="">
                                    <input type="number" class="form-control custom-select" name="Quantity" value="1" style="width:67px;" />
                                    <input type="hidden" name="CartCmd" value="add" />
                                    <button type="submit" style="height:37px;" class="button_type_4 bg_scheme_color r_corners tr_all_hover color_light mw_0 m_right_5 add_to_basket" data-productno="@GetString("Ecom:Product.ID")">@Translate("Ecom:AddToBakset")</button>
                                </form>
                                }   
                            </div>
                        }

                    @*Variants end*@

And some jQuery


function employeeSelect() {
    //Set the value of variant-size to the employee predefined size
    $(".js-variant-size").val($(this).val());
    //Gives the product an orderline field with the employee name.
    $('input[name="EcomOrderLineFieldInput_EmployeeName"]').val($(".js-employee option:selected").data("employee-name"));
}

function variantSelect() {
    //Create string with all selected values seperated by "."
    str = "";
    $(".js-variant-select option:selected").each(function () {
        str += $(this).val() + ".";
    });
    //Create selector for active price table.
    str2 = "div[id='" + str.slice(0, -1) + "']"

    //Hide and display prices for other than active price table.
    $(".js-variant-price").hide();
    $(str2).show();
}

$(".js-employee").change(employeeSelect);
$(".js-employee").change(variantSelect);
$(".js-variant-select").change(variantSelect).trigger("change");

If anyone sees improvment potential let me know... :)

https://tinytake.s3.amazonaws.com/pulse/bjornkamfjord/attachments/8084498/TinyTake18-06-2018-01-40-06.mp4

 
Bjørn Kamfjord
Reply

Well this worked very well!

My second obstacle is that I need some sort of managment module for the users assigned to a "department admin".

So an admin can go to a page where he can add, remove and update the users for his department. I was looking at the "list" view in the Extranet app with "list_groups_users template, but I'm not sure how to tweak it to my needs. Can I get this to get the current users group instead of having to define the group in backend?

I do not want the user to have to login in to backend, it should be able to be done from "my page.

So is there a way to have a frontend user permissions to edit other frontend users?

Any ideas?

 
Nuno Aguiar
Nuno Aguiar
Reply

Hi Bjørn,

 

Can't you make all admins belong to an "Admins" group that have access to that page? Currently we cannot set permissions on a page based on a Smart Search nor a User Repository nor have a group be auto-updated based on a Smart Search (although you can sort-of do it manually), but currently that seems the way to do.

 

When accessing that page, you can use the API to add/remove users from the "Current" group the admin belongs to.

 

Best Regards,

Nuno Aguiar

 
Bjørn Kamfjord
Reply

Yeah thats sort of what i was thinking as well, I just don't really know where to begin. I have a "group admin" for each group.

When accessing that page, you can use the API to add/remove users from the "Current" group the admin belongs to.

Do you have some sort of code example? I know how to get the user group and related users, but what code do I use to update/add/remove users in same group?

 
Nuno Aguiar
Nuno Aguiar
Reply

Hi Bjørn,

 

You need to instanciate a user you want to update by using GetUserById http://doc.dynamicweb.com/api/html/8ab67c99-1342-82dc-4844-eb7ba1418117.htm

 

Once you've done that you can use the RemoveFromGroup method http://doc.dynamicweb.com/api/html/dadaff29-d870-8e34-5f82-ac112cecbbfe.htm with the current group as parameter. 

Save the user and you're done! (You may be removing the user's only/last group, so you may also need to consider that to leave it like that or delete him as well).

 

You may want to do this in an ajax call/handler for a better UX, or simply redirect to the same page with some parameters to trigger the logic and then again to reload the page without the URL parameters, or even to a confirmation page.

 

If you want to invite/add users to the group, it may be trickier since you need to search for existing ones first before adding one.

 

Best Regards,

Nuno Aguiar

 
Bjørn Kamfjord
Reply

Is there not a more "readymade" way accessing users?  It's easy to edit the current user, so I would guess that all the needed functionality already exist..

I have access to the users in the same group or subgroup as an group admin. I can get all the information from the user, now I would like to set / change. Any ideas?

@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@using Dynamicweb.Security;
@using System.Web

@{
    var user = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser();
    var group = user.Groups[0]; //Expection exactly one group - not 0 not 2 or more

    var groupParent = group.Parent;
}

@foreach (LoopItem e in GetLoop("FormValidationErrors"))
{
    <div id="errormessages">
        <ul>

            <li>Error in labele input field "@e.GetString("UserManagement:User.FormValidationError.FieldNiceName"): <a href="javascript:document.getElementById('@e.GetString("UserManagement:User.FormValidationError.FieldName")').focus();">@e.GetString("UserManagement:User.FormValidationError.Message")</a></li>

        </ul>
    </div>
}

@GetString("UserManagement:User.FormStart")

<h2>Detail for '@GetString("UserManagement:User.Name")</h2>
<div class="form-group">
    <label>@Translate("Name", "Name"): </label>
    @GetString("UserManagement:User.Name.Input")

    <label>@Translate("Email", "Email"): </label>
    @GetString("UserManagement:User.Email.Input")

    <label>@Translate("Department", "Department"): </label>
    @GetString("UserManagement:User.Department.Input")

    <label>@Translate("JobTitle", "Jobtitle"): </label>
    @GetString("UserManagement:User.JobTitle.Input")

    <label>@Translate("Company", "Company"): </label>
    @GetString("UserManagement:User.Company.Input")

    @foreach (var cf in GetLoop("UserManagement:User.CustomFields"))
    {
        if (cf.GetString("CustomField.Name").Contains("Size_"))
        {

            <label>@cf.GetString("CustomField.Name") </label>
            @cf.GetString("CustomField.Control")

        }
    }
</div>

<input class="btn btn-primary" type="submit" id="submitter" value="@Translate("updateuser", "Update user")" onclick="@GetString("UserManagement:User.FormSubmilabelref")" />
@GetString("UserManagement:User.FormEnd")

@if (!string.IsNullOrEmpty(GetString("UserManagement:User.DetailUrl")))
{
    <a href="@GetString("UserManagement:User.DetailUrl")">Back to detail view</a>
}

@if (groupParent != null)
{

    var company = group.Parent.Name.Contains("Storkunder");
    var department = group.Parent.Parent.Name.Contains("Storkunder");

    <p>Hei @user.Name, du kan endre ansatte i @group.Name</p>

    <form id="newUser">
        <input type="text" id="name" placeholder="new user name"/>
        <button type="submit" class="btn btn-success">Add new user</button>
    </form>

    if (company)
    {
        foreach (var sg in group.Subgroups)
        {
            <h3>@sg.Name </h3>
            <div class="">
                @foreach (var u in sg.Users)
                {
                    @getUsers(u)
                }

            </div>
        }
    }
    else if (department)
    {
        <div class="">
            @foreach (var u in group.Users)
            {
                @getUsers(u)
            }
        </div>
    }
}

@helper getUsers(Dynamicweb.Security.UserManagement.User u)
{
    string sizeType = GetString("Ecom:Product:Field.SizeType");
    var cfValues = u.CustomFieldValues;
    int i = 0;
    <form class="">
        <div class="form-group">
            <label for="name">@Translate("Name", "Name"):</label>
            <input class="form-control" type="text" id="name" value="@u.Name" />
            <label for="jobtitle">@Translate("JobTitle", "Jobtitle"):</label>
            <input class="form-control" type="text" id="jobtitle" value="@u.JobTitle" />

            @foreach (var field in cfValues)
            {
                if (field.CustomField.Name.Contains("Size_"))
                {
                    i++;
                    <label for="field-@i">@field.CustomField.Name</label>
                    <select class="custom-select" id="field-@i">
                        @foreach (var opt in field.CustomField.Options)
                        {
                            string selected = ((opt.Value.ToString() == field.Value.ToString()) ? "selected" : string.Empty);

                            <option value="@opt.Value">@opt.Key</option>
                        }
                    </select>
                }
            }
            <button class="btn btn-primary m-2" type="submit">Update user</button>
            <button class="btn btn-danger">Remove user</button>
        </div>
    </form>
}
 
Nuno Aguiar
Nuno Aguiar
Reply

Hi Bjørn,

 

I don't know of any better way to get the data you need with the logic in your requirements. That said, I would not have build it the way you have though.

  • I would do all user updates through ajax
    Thus simplifying the markup by not having the form and fields to be submitted, and providing a better UX since you can control alerts/updates in JS raher than a page refresh
  • I would split the "edit user" from the "edit users in my groups and departments

 

Best Regards,

Nuno Aguiar

 

You must be logged in to post in the forum