428 lines
12 KiB
Plaintext

.organization
form#item_form(onsubmit="return editOrganization()")
| {% if can_edit %}
.input-group
label(for='org-name-field') Name
input.item-name.input-transparent#org-name-field(
name="name",
type="text",
placeholder="Organization's name",
value="{{ organization.name | hide_none }}")
.input-group
label(for='org-description-field') Description
textarea.item-description.input-transparent#org-description-field(
name="description",
type="text",
rows=1,
placeholder="Organization's description") {{ organization.description | hide_none }}
.input-group
label(for='org-website-field') Website
input.item-website.input-transparent#org-website-field(
name="website",
type="text",
placeholder="Organization's website",
value="{{ organization.website | hide_none }}")
.input-group
label(for='org-location-field') Location
input.item-location.input-transparent#org-location-field(
name="location",
type="text",
placeholder="Organization's location",
value="{{ organization.location | hide_none }}")
.input-group
label(for='org-ip-ranges-field') IP Ranges
textarea.item-ip-ranges#org-ip-ranges-field(
name="ip_ranges",
type="text",
rows="{{ organization.human_ip_ranges|length|default(1, true) }}",
placeholder="IP ranges in CIDR notation, one on each line",
title="IPv6 like 2a01:1234:abcd:3b::0/64\nIPv4 like 172.16.0.0/16")
| {{ organization.human_ip_ranges | join('\n') }}
p.help-block.
Clients with a matching IP address will be considered part of the organization. IPv4
ranges are always normalized to IPv6 prior to saving. Changes to IP Ranges take up
to an hour to affect already logged-in users.
| {% if can_super_edit %}
.input-group
label(for='org-seat-count-field') Seat count
input.item-location.input-transparent#org-seat-count-field(
name="seat_count",
type="text",
placeholder="Seat count",
value="{{ organization.seat_count | hide_none }}")
p.help-block Users covered by the IP Ranges do not count towards the seat count.
.input-group
label(for='org-roles-field') Roles
input.item-location.input-transparent#org-roles-field(
name="org_roles",
type="text",
placeholder="Organization roles",
value="{{ organization.org_roles | hide_none | sort | join(' ') }}")
| {% endif %}
.input-group.org-admin
label.item-admin-user Organization Administrator
p#admin-name
a(href='javascript:showAdminPicker()', title='Click to choose another administrator') {{ admin_user.full_name }}
p#admin-picker
input#admin-select.form-control(
name='admin_user',
type='text',
placeholder='Search for a new administrator')
a(href='javascript:hideAdminPicker()')
span.text-danger Cancel
script $('#admin-picker').hide();
.input-group
button#item-save.btn.btn-outline-success.btn-block(type='submit')
i.pi-check
| Save Changes
| {% else %}
p.item-name {{ organization.name | hide_none }}
| {% if organization.description %}
p.item-description {{ organization.description | hide_none }}
| {% endif %}
| {% if organization.website %}
p.item-website
a(href='{{ organization.website }}', target='_blank') {{ organization.website }}
| {% endif %}
| {% if organization.location %}
p.item-location {{ organization.location | hide_none }}
| {% endif %}
p.item-admin-user Organization administrator: {{ admin_user.full_name }}
| {% endif %}
hr
h4 Properties
.table.item-properties
.table-body
.table-row.properties-last-updated
.table-cell Last Updated
.table-cell(title='Unable to edit, set by Organization')
| {{ organization._updated | hide_none | pretty_date_time }}
.table-row.properties-seat-count
.table-cell Seat Count
.table-cell(title='Unable to edit, determined by subscription')
| {{ organization.seat_count }} ({{ seats_used }} used)
.table-row.properties-org-roles
.table-cell User roles
.table-cell(title='Unable to edit, determined by subscription')
| {{ organization.org_roles | hide_none | sort | join(', ') }}
hr
h4 Organization members
.members
| {% if can_edit %}
.sharing-users-search
.form-group
input#user-select.form-control(
name='contacts',
type='text',
placeholder='Add member by name')
| {% endif %}
ul.sharing-users-list
| {% for member in members %}
li.sharing-users-item(
data-user-id="{{ member['_id'] }}",
class="{% if current_user.objectid == member['_id'] %}self{% endif %}")
.sharing-users-avatar
img(src="{{ member['avatar'] }}")
.sharing-users-details
span.sharing-users-name
| {{ member['full_name'] }}
| {% if current_user.objectid == member['_id'] %}
small (You)
| {% endif %}
| {% if organization['admin_uid'] == member['_id'] %}
small (admin)
| {% endif %}
span.sharing-users-extra {{ member['username'] }}
.sharing-users-action
| {% if can_edit or current_user.objectid == member['_id'] %}
| {% if current_user.objectid == member['_id'] %}
button.user-remove(title="Leave as member of this organization")
i.pi-trash
| {% else %}
button.user-remove(title="Remove this user from this organization")
i.pi-trash
| {% endif %}
| {% endif %}
| {% else %}
li
p.text-warning No members yet
| {% endfor %}
| {% if organization.unknown_members %}
hr
p Pending Members (i.e. without Blender Cloud account)
ul.sharing-users-list.unknown-members
| {% for email in organization.unknown_members %}
li.sharing-users-item.unknown-member(data-user-email='{{ email }}')
.sharing-users-avatar
img(src="{{ email | gravatar }}")
.sharing-users-details
span.sharing-users-email {{ email }}
.sharing-users-action
| {% if can_edit %}
button.user-remove(title="Remove this user from this organization")
i.pi-trash
| {% endif %}
| {% endfor %}
| {% endif %}
| {% if can_edit %}
br
p Batch-add members by email address:
form#batch_add_form(onsubmit="return batchAddUsers()")
.input-group
textarea.item-description(
name="emails",
type="text",
rows=1,
placeholder="Enter the email addresses separated by space or a new line")
.input-group
button.btn.btn-info.btn-block(type='submit')
i.pi-plus
| Add Members
| {% endif %}
.action-result-panel
| {% if config.DEBUG %}
#item-view-feed
.debug-info
a.debug-info-toggle(role='button',
data-toggle='collapse',
href='#debug-content-organization',
aria-expanded='false',
aria-controls='debug-content-organization')
i.pi-info
| Debug Info
#debug-content-organization.collapse
pre.
{{ organization.to_dict() | pprint }}
| {% endif %}
| {% block footer_scripts %}
| {% if can_edit %}
script.
$(document).ready(function() {
$('#user-select').userSearch(
function (event, hit, dataset) {
var $existing = $('li.sharing-users-item[data-user-id="' + hit.objectID + '"]');
if ($existing.length) {
$existing
.addClass('active')
.delay(1000)
.queue(function() {
$existing.removeClass('active');
$existing.dequeue();
});
toastr.info('User is already member of this organization');
}
else {
addUser(hit.objectID);
}
}
);
$('#admin-select').userSearch(
function (event, hit, dataset) {
setAdmin(hit.objectID, hit.full_name);
}
);
});
function addUser(userId) {
if (!userId || userId.length == 0) {
toastr.error('Please select a user from the list');
return;
}
patchOrganization({
op: 'assign-user',
user_id: userId
})
.done(function (data) {
setTimeout(function(){ $('.sharing-users-item').removeClass('added');}, 350);
toastr.success('Member added to this organization!');
// TODO fsiddi: avoid the reloading of the entire page?
window.location.reload();
})
.fail(function (err) {
var msg = xhrErrorResponseMessage(err);
toastr.error('Could not add member: ' + msg);
});
};
function setAdmin(user_id, full_name) {
if (!user_id || user_id.length == 0) {
toastr.error('Please select a user from the list');
return;
}
if (!confirm("Are you sure you want to transfer administrator privileges to " + full_name + "?")) {
hideAdminPicker();
toastr.warning('Cancelled administrative transfer.');
return;
}
patchOrganization({
op: 'assign-admin',
user_id: user_id
})
.done(function (data) {
window.location.reload();
toastr.info('Updated admin user');
})
.fail(function (err) {
var msg = xhrErrorResponseMessage(err);
toastr.error('Could not add member: ' + msg);
});
};
function editOrganization() {
var $form = $('#item_form');
var new_name = $form.find('*[name="name"]').val();
{% if can_super_edit %}
var org_roles_str = $form.find('*[name="org_roles"]').val().trim();
var org_roles = Array();
if (org_roles_str.length) org_roles = org_roles_str.split(/\s/);
{% endif %}
var ipr = $form.find('*[name="ip_ranges"]').val().trim();
if (ipr == '') ip_ranges = Array();
else ip_ranges = ipr.split(/\s/);
patchOrganization({
op: 'edit-from-web',
name: new_name,
description: $form.find('*[name="description"]').val(),
website: $form.find('*[name="website"]').val(),
location: $form.find('*[name="location"]').val(),
ip_ranges: ip_ranges,
{% if can_super_edit %}
seat_count: parseInt($form.find('*[name="seat_count"]').val()),
org_roles: org_roles,
{% endif %}
})
.done(function() {
$('span.organization-name-{{ organization._id }}').text(new_name);
item_open('{{ organization._id }}', false);
})
.fail(function(err) {
var msg = xhrErrorResponseMessage(err);
toastr.error('Error editing organization: ' + msg);
})
;
return false;
}
function batchAddUsers() {
var $form = $('#batch_add_form');
var emails = $form.find('*[name="emails"]').val().split(/\s/);
console.log(emails);
patchOrganization({
op: 'assign-users',
emails: emails,
})
.done(function() {
item_open('{{ organization._id }}', false);
})
.fail(function(err) {
var msg = xhrErrorResponseMessage(err);
toastr.error('Error adding members: ' + msg);
})
;
return false;
}
function showAdminPicker() {
$('#admin-name').hide();
$('#admin-picker').show(function() {
$(this).find('input').focus();
});
}
function hideAdminPicker() {
$('#admin-picker').hide();
$('#admin-name').show();
}
| {% endif %}
script.
$(document).ready(function() {
$('body').off('click', '.user-remove'); // remove previous handlers.
$('body').on('click', '.user-remove', function(e) {
var user_id = $(this).closest('*[data-user-id]').data('user-id');
var user_email = $(this).closest('*[data-user-email]').data('user-email');
removeUser(user_id, user_email);
});
});
function patchOrganization(patch) {
if (typeof patch == 'undefined') {
throw 'patchOrganization(undefined) called';
}
if (console) console.log('patchOrganization', patch);
var promise = $.ajax({
url: '/api/organizations/{{ organization._id }}',
method: 'PATCH',
contentType: 'application/json',
data: JSON.stringify(patch),
})
.fail(function(err) {
if (console) console.log('Error patching: ', err);
})
;
return promise;
}
function removeUser(user_id, email) {
if (typeof user_id == 'undefined' && typeof email == 'undefined') {
throw "removeUser(undefined, undefined) called";
}
var organization_id = '{{ organization._id }}';
var patch = {op: 'remove-user'};
if (typeof user_id !== 'undefined') {
patch.user_id = user_id;
}
if (typeof email !== 'undefined') {
patch.email = String(email);
}
patchOrganization(patch)
.done(function() {
$("ul.sharing-users-list").find("[data-user-id='" + user_id + "']").remove();
if ('{{ current_user.user_id }}' == user_id) {
// User removed self, so we cannot open this organization again.
$('#organization-{{ organization._id}}').remove();
toastr.success('You left the organization.')
} else {
item_open('{{ organization._id }}', false);
toastr.success('User removed from this organization');
}
}).fail(function (data) {
var msg = xhrErrorResponseMessage(data);
toastr.error('Error removing user: ' + msg);
});
}
| {% endblock %}