mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2025-07-03 04:37:46 +00:00
Merge and resolve the conflicts from master
This commit is contained in:
279
app/models.py
279
app/models.py
@ -355,25 +355,48 @@ class User(db.Model):
|
||||
db.session.rollback()
|
||||
return False
|
||||
|
||||
def get_account_query(self):
|
||||
"""
|
||||
Get query for account to which the user is associated.
|
||||
"""
|
||||
return db.session.query(Account) \
|
||||
.outerjoin(AccountUser, Account.id==AccountUser.account_id) \
|
||||
.filter(AccountUser.user_id==self.id)
|
||||
|
||||
def get_account(self):
|
||||
"""
|
||||
Get all accounts to which the user is associated.
|
||||
"""
|
||||
return self.get_account_query()
|
||||
|
||||
def get_domain_query(self):
|
||||
return db.session.query(User, DomainUser, Domain) \
|
||||
.filter(User.id == self.id) \
|
||||
.filter(User.id == DomainUser.user_id) \
|
||||
.filter(Domain.id == DomainUser.domain_id)
|
||||
"""
|
||||
Get query for domain to which the user has access permission.
|
||||
This includes direct domain permission AND permission through
|
||||
account membership
|
||||
"""
|
||||
return db.session.query(Domain) \
|
||||
.outerjoin(DomainUser, Domain.id==DomainUser.domain_id) \
|
||||
.outerjoin(Account, Domain.account_id==Account.id) \
|
||||
.outerjoin(AccountUser, Account.id==AccountUser.account_id) \
|
||||
.filter(db.or_(DomainUser.user_id==User.id, AccountUser.user_id==User.id)) \
|
||||
.filter(User.id==self.id)
|
||||
|
||||
def get_domain(self):
|
||||
"""
|
||||
Get domains which user has permission to
|
||||
access
|
||||
"""
|
||||
return [q[2] for q in self.get_domain_query()]
|
||||
return self.get_domain_query()
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Delete a user
|
||||
"""
|
||||
# revoke all user privileges first
|
||||
# revoke all user privileges and account associations first
|
||||
self.revoke_privilege()
|
||||
for a in self.get_account():
|
||||
a.revoke_privileges_by_id(self.id)
|
||||
|
||||
try:
|
||||
User.query.filter(User.username == self.username).delete()
|
||||
@ -426,6 +449,161 @@ class User(db.Model):
|
||||
return False
|
||||
|
||||
|
||||
class Account(db.Model):
|
||||
__tablename__ = 'account'
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
name = db.Column(db.String(40), index=True, unique=True, nullable=False)
|
||||
description = db.Column(db.String(128))
|
||||
contact = db.Column(db.String(128))
|
||||
mail = db.Column(db.String(128))
|
||||
domains = db.relationship("Domain", back_populates="account")
|
||||
|
||||
def __init__(self, name=None, description=None, contact=None, mail=None):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.contact = contact
|
||||
self.mail = mail
|
||||
|
||||
if self.name is not None:
|
||||
self.name = ''.join(c for c in self.name.lower() if c in "abcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
||||
def __repr__(self):
|
||||
return '<Account {0}r>'.format(self.name)
|
||||
|
||||
def get_name_by_id(self, account_id):
|
||||
"""
|
||||
Convert account_id to account_name
|
||||
"""
|
||||
account = Account.query.filter(Account.id == account_id).first()
|
||||
if account is None:
|
||||
return ''
|
||||
|
||||
return account.name
|
||||
|
||||
def get_id_by_name(self, account_name):
|
||||
"""
|
||||
Convert account_name to account_id
|
||||
"""
|
||||
account = Account.query.filter(Account.name == account_name).first()
|
||||
if account is None:
|
||||
return None
|
||||
|
||||
return account.id
|
||||
|
||||
def unassociate_domains(self):
|
||||
"""
|
||||
Remove associations to this account from all domains
|
||||
"""
|
||||
account = Account.query.filter(Account.name == self.name).first()
|
||||
for domain in account.domains:
|
||||
domain.assoc_account(None)
|
||||
|
||||
def create_account(self):
|
||||
"""
|
||||
Create a new account
|
||||
"""
|
||||
# Sanity check - account name
|
||||
if self.name == "":
|
||||
return {'status': False, 'msg': 'No account name specified'}
|
||||
|
||||
# check that account name is not already used
|
||||
account = Account.query.filter(Account.name == self.name).first()
|
||||
if account:
|
||||
return {'status': False, 'msg': 'Account already exists'}
|
||||
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
return {'status': True, 'msg': 'Account created successfully'}
|
||||
|
||||
def update_account(self):
|
||||
"""
|
||||
Update an existing account
|
||||
"""
|
||||
# Sanity check - account name
|
||||
if self.name == "":
|
||||
return {'status': False, 'msg': 'No account name specified'}
|
||||
|
||||
# read account and check that it exists
|
||||
account = Account.query.filter(Account.name == self.name).first()
|
||||
if not account:
|
||||
return {'status': False, 'msg': 'Account does not exist'}
|
||||
|
||||
account.description = self.description
|
||||
account.contact = self.contact
|
||||
account.mail = self.mail
|
||||
|
||||
db.session.commit()
|
||||
return {'status': True, 'msg': 'Account updated successfully'}
|
||||
|
||||
def delete_account(self):
|
||||
"""
|
||||
Delete an account
|
||||
"""
|
||||
# unassociate all domains and users first
|
||||
self.unassociate_domains()
|
||||
self.grant_privileges([])
|
||||
|
||||
try:
|
||||
Account.query.filter(Account.name == self.name).delete()
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
except:
|
||||
db.session.rollback()
|
||||
logging.error('Cannot delete account {0} from DB'.format(self.username))
|
||||
return False
|
||||
|
||||
def get_user(self):
|
||||
"""
|
||||
Get users (id) associated with this account
|
||||
"""
|
||||
user_ids = []
|
||||
query = db.session.query(AccountUser, Account).filter(User.id==AccountUser.user_id).filter(Account.id==AccountUser.account_id).filter(Account.name==self.name).all()
|
||||
for q in query:
|
||||
user_ids.append(q[0].user_id)
|
||||
return user_ids
|
||||
|
||||
def grant_privileges(self, new_user_list):
|
||||
"""
|
||||
Reconfigure account_user table
|
||||
"""
|
||||
account_id = self.get_id_by_name(self.name)
|
||||
|
||||
account_user_ids = self.get_user()
|
||||
new_user_ids = [u.id for u in User.query.filter(User.username.in_(new_user_list)).all()] if new_user_list else []
|
||||
|
||||
removed_ids = list(set(account_user_ids).difference(new_user_ids))
|
||||
added_ids = list(set(new_user_ids).difference(account_user_ids))
|
||||
|
||||
try:
|
||||
for uid in removed_ids:
|
||||
AccountUser.query.filter(AccountUser.user_id == uid).filter(AccountUser.account_id==account_id).delete()
|
||||
db.session.commit()
|
||||
except:
|
||||
db.session.rollback()
|
||||
logging.error('Cannot revoke user privielges on account {0}'.format(self.name))
|
||||
|
||||
try:
|
||||
for uid in added_ids:
|
||||
au = AccountUser(account_id, uid)
|
||||
db.session.add(au)
|
||||
db.session.commit()
|
||||
except:
|
||||
db.session.rollback()
|
||||
logging.error('Cannot grant user privileges to account {0}'.format(self.name))
|
||||
|
||||
def revoke_privileges_by_id(self, user_id):
|
||||
"""
|
||||
Remove a single user from prigilege list based on user_id
|
||||
"""
|
||||
new_uids = [u for u in self.get_user() if u != user_id]
|
||||
users = []
|
||||
for uid in new_uids:
|
||||
users.append(User(id=uid).get_user_info_by_id().username)
|
||||
|
||||
self.grant_privileges(users)
|
||||
|
||||
|
||||
class Role(db.Model):
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
name = db.Column(db.String(64), index=True, unique=True)
|
||||
@ -446,6 +624,7 @@ class Role(db.Model):
|
||||
def __repr__(self):
|
||||
return '<Role {0}r>'.format(self.name)
|
||||
|
||||
|
||||
class DomainSetting(db.Model):
|
||||
__tablename__ = 'domain_setting'
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
@ -485,9 +664,11 @@ class Domain(db.Model):
|
||||
notified_serial = db.Column(db.Integer)
|
||||
last_check = db.Column(db.Integer)
|
||||
dnssec = db.Column(db.Integer)
|
||||
account_id = db.Column(db.Integer, db.ForeignKey('account.id'))
|
||||
account = db.relationship("Account", back_populates="domains")
|
||||
settings = db.relationship('DomainSetting', back_populates='domain')
|
||||
|
||||
def __init__(self, id=None, name=None, master=None, type='NATIVE', serial=None, notified_serial=None, last_check=None, dnssec=None):
|
||||
def __init__(self, id=None, name=None, master=None, type='NATIVE', serial=None, notified_serial=None, last_check=None, dnssec=None, account_id=None):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.master = master
|
||||
@ -496,6 +677,7 @@ class Domain(db.Model):
|
||||
self.notified_serial = notified_serial
|
||||
self.last_check = last_check
|
||||
self.dnssec = dnssec
|
||||
self.account_id = account_id
|
||||
|
||||
def __repr__(self):
|
||||
return '<Domain {0}>'.format(self.name)
|
||||
@ -575,6 +757,7 @@ class Domain(db.Model):
|
||||
|
||||
# update/add new domain
|
||||
for data in jdata:
|
||||
account_id = Account().get_id_by_name(data['account'])
|
||||
d = dict_db_domain.get(data['name'].rstrip('.'), None)
|
||||
changed = False
|
||||
if d:
|
||||
@ -584,7 +767,8 @@ class Domain(db.Model):
|
||||
or d.serial != data['serial']
|
||||
or d.notified_serial != data['notified_serial']
|
||||
or d.last_check != ( 1 if data['last_check'] else 0 )
|
||||
or d.dnssec != data['dnssec'] ):
|
||||
or d.dnssec != data['dnssec']
|
||||
or d.account_id != account_id ):
|
||||
|
||||
d.master = str(data['masters'])
|
||||
d.type = data['kind']
|
||||
@ -592,6 +776,7 @@ class Domain(db.Model):
|
||||
d.notified_serial = data['notified_serial']
|
||||
d.last_check = 1 if data['last_check'] else 0
|
||||
d.dnssec = 1 if data['dnssec'] else 0
|
||||
d.account_id = account_id
|
||||
changed = True
|
||||
|
||||
else:
|
||||
@ -604,19 +789,20 @@ class Domain(db.Model):
|
||||
d.notified_serial = data['notified_serial']
|
||||
d.last_check = data['last_check']
|
||||
d.dnssec = 1 if data['dnssec'] else 0
|
||||
d.account_id = account_id
|
||||
db.session.add(d)
|
||||
changed = True
|
||||
if changed:
|
||||
try:
|
||||
db.session.commit()
|
||||
except:
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return {'status': 'ok', 'msg': 'Domain table has been updated successfully'}
|
||||
except Exception as e:
|
||||
logging.error('Can not update domain table. Error: {0}'.format(e))
|
||||
return {'status': 'error', 'msg': 'Can not update domain table'}
|
||||
|
||||
def add(self, domain_name, domain_type, soa_edit_api, domain_ns=[], domain_master_ips=[]):
|
||||
def add(self, domain_name, domain_type, soa_edit_api, domain_ns=[], domain_master_ips=[], account_name=None):
|
||||
"""
|
||||
Add a domain to power dns
|
||||
"""
|
||||
@ -638,7 +824,8 @@ class Domain(db.Model):
|
||||
"kind": domain_type,
|
||||
"masters": domain_master_ips,
|
||||
"nameservers": domain_ns,
|
||||
"soa_edit_api": soa_edit_api
|
||||
"soa_edit_api": soa_edit_api,
|
||||
"account": account_name
|
||||
}
|
||||
|
||||
try:
|
||||
@ -647,6 +834,7 @@ class Domain(db.Model):
|
||||
logging.error(jdata['error'])
|
||||
return {'status': 'error', 'msg': jdata['error']}
|
||||
else:
|
||||
self.update()
|
||||
logging.info('Added domain {0} successfully'.format(domain_name))
|
||||
return {'status': 'ok', 'msg': 'Added domain successfully'}
|
||||
except Exception as e:
|
||||
@ -798,7 +986,6 @@ class Domain(db.Model):
|
||||
db.session.rollback()
|
||||
logging.error('Cannot grant user privielges to domain {0}'.format(self.name))
|
||||
|
||||
|
||||
def update_from_master(self, domain_name):
|
||||
"""
|
||||
Update records from Master DNS server
|
||||
@ -900,6 +1087,60 @@ class Domain(db.Model):
|
||||
else:
|
||||
return {'status': 'error', 'msg': 'This domain doesnot exist'}
|
||||
|
||||
def assoc_account(self, account_id):
|
||||
"""
|
||||
Associate domain with a domain, specified by account id
|
||||
"""
|
||||
domain_name = self.name
|
||||
|
||||
# Sanity check - domain name
|
||||
if domain_name == "":
|
||||
return {'status': False, 'msg': 'No domain name specified'}
|
||||
|
||||
# read domain and check that it exists
|
||||
domain = Domain.query.filter(Domain.name == domain_name).first()
|
||||
if not domain:
|
||||
return {'status': False, 'msg': 'Domain does not exist'}
|
||||
|
||||
headers = {}
|
||||
headers['X-API-Key'] = PDNS_API_KEY
|
||||
|
||||
account_name = Account().get_name_by_id(account_id)
|
||||
|
||||
post_data = {
|
||||
"account": account_name
|
||||
}
|
||||
|
||||
try:
|
||||
jdata = utils.fetch_json(
|
||||
urljoin(PDNS_STATS_URL, API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain_name)), headers=headers,
|
||||
method='PUT', data=post_data)
|
||||
|
||||
if 'error' in jdata.keys():
|
||||
logging.error(jdata['error'])
|
||||
return {'status': 'error', 'msg': jdata['error']}
|
||||
|
||||
else:
|
||||
self.update()
|
||||
logging.info('account changed for domain {0} successfully'.format(domain_name))
|
||||
return {'status': 'ok', 'msg': 'account changed successfully'}
|
||||
|
||||
except Exception as e:
|
||||
logging.debug(e)
|
||||
logging.debug(traceback.format_exc())
|
||||
logging.error('Cannot change account for domain {0}'.format(domain_name))
|
||||
return {'status': 'error', 'msg': 'Cannot change account for this domain.'}
|
||||
|
||||
return {'status': True, 'msg': 'Domain association successful'}
|
||||
|
||||
def get_account(self):
|
||||
"""
|
||||
Get current account associated with this domain
|
||||
"""
|
||||
domain = Domain.query.filter(Domain.name == self.name).first()
|
||||
|
||||
return domain.account
|
||||
|
||||
|
||||
class DomainUser(db.Model):
|
||||
__tablename__ = 'domain_user'
|
||||
@ -915,6 +1156,20 @@ class DomainUser(db.Model):
|
||||
return '<Domain_User {0} {1}>'.format(self.domain_id, self.user_id)
|
||||
|
||||
|
||||
class AccountUser(db.Model):
|
||||
__tablename__ = 'account_user'
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
account_id = db.Column(db.Integer, db.ForeignKey('account.id'), nullable = False)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable = False)
|
||||
|
||||
def __init__(self, account_id, user_id):
|
||||
self.account_id = account_id
|
||||
self.user_id = user_id
|
||||
|
||||
def __repr__(self):
|
||||
return '<Account_User {0} {1}>'.format(self.account_id, self.user_id)
|
||||
|
||||
|
||||
class Record(object):
|
||||
"""
|
||||
This is not a model, it's just an object
|
||||
|
Reference in New Issue
Block a user