Merge pull request #1231 from AdvanticGmbH/assoc_domain_list

Allow to manage associated domains under account edit
This commit is contained in:
Matt Scott 2023-02-17 12:04:16 -05:00 committed by GitHub
commit ba14d52c8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 111 additions and 40 deletions

View File

@ -2,6 +2,7 @@ import json
import re import re
import traceback import traceback
from flask import current_app from flask import current_app
from flask_login import current_user
from urllib.parse import urljoin from urllib.parse import urljoin
from distutils.util import strtobool from distutils.util import strtobool
@ -851,6 +852,7 @@ class Domain(db.Model):
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'} headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
account_name_old = Account().get_name_by_id(domain.account_id)
account_name = Account().get_name_by_id(account_id) account_name = Account().get_name_by_id(account_id)
post_data = {"account": account_name} post_data = {"account": account_name}
@ -874,6 +876,13 @@ class Domain(db.Model):
self.update() self.update()
msg_str = 'Account changed for domain {0} successfully' msg_str = 'Account changed for domain {0} successfully'
current_app.logger.info(msg_str.format(domain_name)) current_app.logger.info(msg_str.format(domain_name))
history = History(msg='Update domain {0} associate account {1}'.format(domain.name, 'none' if account_name == '' else account_name),
detail = json.dumps({
'assoc_account': 'None' if account_name == '' else account_name,
'dissoc_account': 'None' if account_name_old == '' else account_name_old
}),
created_by=current_user.username)
history.add()
return {'status': 'ok', 'msg': 'account changed successfully'} return {'status': 'ok', 'msg': 'account changed successfully'}
except Exception as e: except Exception as e:

View File

@ -610,14 +610,21 @@ def manage_user():
@operator_role_required @operator_role_required
def edit_account(account_name=None): def edit_account(account_name=None):
users = User.query.all() users = User.query.all()
account = Account.query.filter(
Account.name == account_name).first()
all_accounts = Account.query.all()
accounts = {acc.id: acc for acc in all_accounts}
domains = Domain.query.all()
if request.method == 'GET': if request.method == 'GET':
if account_name is None: if account_name is None or not account:
return render_template('admin_edit_account.html', return render_template('admin_edit_account.html',
account=None,
account_user_ids=[], account_user_ids=[],
users=users, users=users,
domains=domains,
accounts=accounts,
create=1) create=1)
else: else:
account = Account.query.filter( account = Account.query.filter(
Account.name == account_name).first() Account.name == account_name).first()
@ -626,11 +633,14 @@ def edit_account(account_name=None):
account=account, account=account,
account_user_ids=account_user_ids, account_user_ids=account_user_ids,
users=users, users=users,
domains=domains,
accounts=accounts,
create=0) create=0)
if request.method == 'POST': if request.method == 'POST':
fdata = request.form fdata = request.form
new_user_list = request.form.getlist('account_multi_user') new_user_list = request.form.getlist('account_multi_user')
new_domain_list = request.form.getlist('account_domains')
# on POST, synthesize account and account_user_ids from form data # on POST, synthesize account and account_user_ids from form data
if not account_name: if not account_name:
@ -654,6 +664,8 @@ def edit_account(account_name=None):
account=account, account=account,
account_user_ids=account_user_ids, account_user_ids=account_user_ids,
users=users, users=users,
domains=domains,
accounts=accounts,
create=create, create=create,
invalid_accountname=True) invalid_accountname=True)
@ -662,19 +674,33 @@ def edit_account(account_name=None):
account=account, account=account,
account_user_ids=account_user_ids, account_user_ids=account_user_ids,
users=users, users=users,
domains=domains,
accounts=accounts,
create=create, create=create,
duplicate_accountname=True) duplicate_accountname=True)
result = account.create_account() result = account.create_account()
history = History(msg='Create account {0}'.format(account.name),
created_by=current_user.username)
else: else:
result = account.update_account() result = account.update_account()
history = History(msg='Update account {0}'.format(account.name),
created_by=current_user.username)
if result['status']: if result['status']:
account = Account.query.filter(
Account.name == account_name).first()
old_domains = Domain.query.filter(Domain.account_id == account.id).all()
for domain_name in new_domain_list:
domain = Domain.query.filter(
Domain.name == domain_name).first()
if account.id != domain.account_id:
Domain(name=domain_name).assoc_account(account.id)
for domain in old_domains:
if domain.name not in new_domain_list:
Domain(name=domain.name).assoc_account(None)
history = History(msg='{0} account {1}'.format('Create' if create else 'Update', account.name),
created_by=current_user.username)
account.grant_privileges(new_user_list) account.grant_privileges(new_user_list)
history.add() history.add()
return redirect(url_for('admin.manage_account')) return redirect(url_for('admin.manage_account'))
@ -890,6 +916,16 @@ class DetailedHistory():
''', ''',
history_status=DetailedHistory.get_key_val(detail_dict, 'status'), history_status=DetailedHistory.get_key_val(detail_dict, 'status'),
history_msg=DetailedHistory.get_key_val(detail_dict, 'msg')) history_msg=DetailedHistory.get_key_val(detail_dict, 'msg'))
elif 'Update domain' in history.msg and 'associate account' in history.msg: # When an account gets associated or dissociate with domains
self.detailed_msg = render_template_string('''
<table class="table table-bordered table-striped">
<tr><td>Associate: </td><td>{{ history_assoc_account }}</td></tr>
<tr><td>Dissociate:</td><td>{{ history_dissoc_account }}</td></tr>
</table>
''',
history_assoc_account=DetailedHistory.get_key_val(detail_dict, 'assoc_account'),
history_dissoc_account=DetailedHistory.get_key_val(detail_dict, 'dissoc_account'))
# check for lower key as well for old databases # check for lower key as well for old databases
@staticmethod @staticmethod

View File

@ -90,6 +90,28 @@
</select> </select>
</div> </div>
</div> </div>
<div class="box-body">
<p>Domains on the right are associated with the account. Red marked domain names are already associated with other accounts.
Moving already associated domains to this account will overwrite the previous associated account.
</p>
<p>Hover over the red domain names to show the associated account. Click on domains to move between columns.</p>
<div class="form-group col-xs-2">
<select multiple="multiple" class="form-control" id="account_domains"
name="account_domains">
{% for domain in domains %}
{% if account != None and domain.account_id != None and account.id != domain.account_id %}
{% with account_id=domain.account_id %}
<option style="color: red" data-toggle="tooltip" title="Associated with: {{ accounts[account_id].name }}"
value="{{ domain.name }}">{{ domain.name }}</option>
{% endwith %}
{% else %}
<option {% if account.id == domain.account_id %}selected{% endif %}
value="{{ domain.name }}">{{ domain.name }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
<div class="box-footer"> <div class="box-footer">
<button type="submit" <button type="submit"
class="btn btn-flat btn-primary">{% if create %}Create{% else %}Update{% endif %} class="btn btn-flat btn-primary">{% if create %}Create{% else %}Update{% endif %}
@ -127,40 +149,44 @@
{% endblock %} {% endblock %}
{% block extrascripts %} {% block extrascripts %}
<script> <script>
$("#account_multi_user").multiSelect({ function addMultiSelect(id, placeholder) {
selectableHeader: "<input type='text' class='search-input' autocomplete='off' placeholder='Username'>", $(id).multiSelect({
selectionHeader: "<input type='text' class='search-input' autocomplete='off' placeholder='Username'>", selectableHeader: `<input type='text' class='search-input' autocomplete='off' placeholder='${placeholder}'>`,
afterInit: function (ms) { selectionHeader: `<input type='text' class='search-input' autocomplete='off' placeholder='${placeholder}'>`,
var that = this, afterInit: function (ms) {
$selectableSearch = that.$selectableUl.prev(), var that = this,
$selectionSearch = that.$selectionUl.prev(), $selectableSearch = that.$selectableUl.prev(),
selectableSearchString = '#' + that.$container.attr('id') + ' .ms-elem-selectable:not(.ms-selected)', $selectionSearch = that.$selectionUl.prev(),
selectionSearchString = '#' + that.$container.attr('id') + ' .ms-elem-selection.ms-selected'; selectableSearchString = '#' + that.$container.attr('id') + ' .ms-elem-selectable:not(.ms-selected)',
selectionSearchString = '#' + that.$container.attr('id') + ' .ms-elem-selection.ms-selected';
that.qs1 = $selectableSearch.quicksearch(selectableSearchString) that.qs1 = $selectableSearch.quicksearch(selectableSearchString)
.on('keydown', function (e) { .on('keydown', function (e) {
if (e.which === 40) { if (e.which === 40) {
that.$selectableUl.focus(); that.$selectableUl.focus();
return false; return false;
} }
}); });
that.qs2 = $selectionSearch.quicksearch(selectionSearchString) that.qs2 = $selectionSearch.quicksearch(selectionSearchString)
.on('keydown', function (e) { .on('keydown', function (e) {
if (e.which == 40) { if (e.which == 40) {
that.$selectionUl.focus(); that.$selectionUl.focus();
return false; return false;
} }
}); });
}, },
afterSelect: function () { afterSelect: function () {
this.qs1.cache(); this.qs1.cache();
this.qs2.cache(); this.qs2.cache();
}, },
afterDeselect: function () { afterDeselect: function () {
this.qs1.cache(); this.qs1.cache();
this.qs2.cache(); this.qs2.cache();
} }
}); });
}
addMultiSelect("#account_multi_user", "Username")
addMultiSelect("#account_domains", "Domain")
</script> </script>
{% endblock %} {% endblock %}