Add basic support for managing, and accepting API tokens
also various other changes in pursuit of that. so far tokens are only accepted by web API and not traditional web app
This commit is contained in:
parent
85947878c4
commit
c002d3d182
9 changed files with 318 additions and 26 deletions
|
@ -2282,9 +2282,15 @@ class MasterView(View):
|
|||
if info and info.markdown_text:
|
||||
return info.markdown_text
|
||||
|
||||
def can_edit_help(self):
|
||||
if self.has_perm('edit_help'):
|
||||
return True
|
||||
if self.request.has_perm('common.edit_help'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def edit_help(self):
|
||||
if (not self.has_perm('edit_help')
|
||||
and not self.request.has_perm('common.edit_help')):
|
||||
if not self.can_edit_help():
|
||||
raise self.forbidden()
|
||||
|
||||
model = self.model
|
||||
|
@ -2317,8 +2323,7 @@ class MasterView(View):
|
|||
return {'ok': True}
|
||||
|
||||
def edit_field_help(self):
|
||||
if (not self.has_perm('edit_help')
|
||||
and not self.request.has_perm('common.edit_help')):
|
||||
if not self.can_edit_help():
|
||||
raise self.forbidden()
|
||||
|
||||
model = self.model
|
||||
|
@ -2371,8 +2376,7 @@ class MasterView(View):
|
|||
'grid_index': self.grid_index,
|
||||
'help_url': self.get_help_url(),
|
||||
'help_markdown': self.get_help_markdown(),
|
||||
'can_edit_help': (self.has_perm('edit_help')
|
||||
or self.request.has_perm('common.edit_help')),
|
||||
'can_edit_help': self.can_edit_help(),
|
||||
'quickie': None,
|
||||
}
|
||||
|
||||
|
@ -2638,16 +2642,16 @@ class MasterView(View):
|
|||
elif is_primary:
|
||||
btn_kw['type'] = 'is-primary'
|
||||
|
||||
if icon_left:
|
||||
btn_kw['icon_left'] = icon_left
|
||||
elif is_external:
|
||||
btn_kw['icon_left'] = 'external-link-alt'
|
||||
elif url:
|
||||
btn_kw['icon_left'] = 'eye'
|
||||
|
||||
if url:
|
||||
btn_kw['href'] = url
|
||||
|
||||
if icon_left:
|
||||
btn_kw['icon_left'] = icon_left
|
||||
elif is_external:
|
||||
btn_kw['icon_left'] = 'external-link-alt'
|
||||
else:
|
||||
btn_kw['icon_left'] = 'eye'
|
||||
|
||||
if target:
|
||||
btn_kw['target'] = target
|
||||
elif is_external:
|
||||
|
@ -4017,8 +4021,7 @@ class MasterView(View):
|
|||
'action_url': self.request.current_route_url(_query=None),
|
||||
'assume_local_times': self.has_local_times,
|
||||
'route_prefix': route_prefix,
|
||||
'can_edit_help': (self.has_perm('edit_help')
|
||||
or self.request.has_perm('common.edit_help')),
|
||||
'can_edit_help': self.can_edit_help(),
|
||||
}
|
||||
|
||||
if defaults['can_edit_help']:
|
||||
|
|
|
@ -38,6 +38,7 @@ from webhelpers2.html import HTML, tags
|
|||
from tailbone import forms
|
||||
from tailbone.views import MasterView, View
|
||||
from tailbone.views.principal import PrincipalMasterView, PermissionsRenderer
|
||||
from tailbone.util import raw_datetime
|
||||
|
||||
|
||||
class UserView(PrincipalMasterView):
|
||||
|
@ -51,6 +52,10 @@ class UserView(PrincipalMasterView):
|
|||
touchable = True
|
||||
mergeable = True
|
||||
|
||||
labels = {
|
||||
'api_tokens': "API Tokens",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
'username',
|
||||
'person',
|
||||
|
@ -68,6 +73,7 @@ class UserView(PrincipalMasterView):
|
|||
'active_sticky',
|
||||
'set_password',
|
||||
'prevent_password_change',
|
||||
'api_tokens',
|
||||
'roles',
|
||||
'permissions',
|
||||
]
|
||||
|
@ -218,6 +224,17 @@ class UserView(PrincipalMasterView):
|
|||
# if self.creating:
|
||||
# f.set_required('password')
|
||||
|
||||
# api_tokens
|
||||
if self.creating or self.editing:
|
||||
f.remove('api_tokens')
|
||||
elif self.has_perm('manage_api_tokens'):
|
||||
f.set_renderer('api_tokens', self.render_api_tokens)
|
||||
f.set_vuejs_component_kwargs(**{':apiTokens': 'apiTokens',
|
||||
'@api-new-token': 'apiNewToken',
|
||||
'@api-token-delete': 'apiTokenDelete'})
|
||||
else:
|
||||
f.remove('api_tokens')
|
||||
|
||||
# roles
|
||||
f.set_renderer('roles', self.render_roles)
|
||||
if self.creating or self.editing:
|
||||
|
@ -260,6 +277,75 @@ class UserView(PrincipalMasterView):
|
|||
if self.viewing or self.deleting:
|
||||
f.remove('set_password')
|
||||
|
||||
def render_api_tokens(self, user, field):
|
||||
route_prefix = self.get_route_prefix()
|
||||
permission_prefix = self.get_permission_prefix()
|
||||
|
||||
factory = self.get_grid_factory()
|
||||
g = factory(
|
||||
key='{}.api_tokens'.format(route_prefix),
|
||||
data=[],
|
||||
columns=['description', 'created'],
|
||||
main_actions=[
|
||||
self.make_action('delete', icon='trash',
|
||||
click_handler="$emit('api-token-delete', props.row)")])
|
||||
|
||||
button = self.make_buefy_button("New", is_primary=True,
|
||||
icon_left='plus',
|
||||
**{'@click': "$emit('api-new-token')"})
|
||||
|
||||
table = HTML.literal(
|
||||
g.render_buefy_table_element(data_prop='apiTokens'))
|
||||
|
||||
return HTML.tag('div', c=[button, table])
|
||||
|
||||
def add_api_token(self):
|
||||
user = self.get_instance()
|
||||
data = self.request.json_body
|
||||
|
||||
token = self.auth_handler.add_api_token(user, data['description'])
|
||||
self.Session.flush()
|
||||
|
||||
return {'ok': True,
|
||||
'raw_token': token.token_string,
|
||||
'tokens': self.get_api_tokens(user)}
|
||||
|
||||
def delete_api_token(self):
|
||||
model = self.model
|
||||
user = self.get_instance()
|
||||
data = self.request.json_body
|
||||
|
||||
token = self.Session.get(model.UserAPIToken, data['uuid'])
|
||||
if not token:
|
||||
return {'error': "API token not found"}
|
||||
|
||||
if token.user is not user:
|
||||
return {'error': "API token not found"}
|
||||
|
||||
self.auth_handler.delete_api_token(token)
|
||||
self.Session.flush()
|
||||
|
||||
return {'ok': True,
|
||||
'tokens': self.get_api_tokens(user)}
|
||||
|
||||
def template_kwargs_view(self, **kwargs):
|
||||
kwargs = super(UserView, self).template_kwargs_view(**kwargs)
|
||||
user = kwargs['instance']
|
||||
|
||||
kwargs['api_tokens_data'] = self.get_api_tokens(user)
|
||||
|
||||
return kwargs
|
||||
|
||||
def get_api_tokens(self, user):
|
||||
tokens = []
|
||||
for token in reversed(user.api_tokens):
|
||||
tokens.append({
|
||||
'uuid': token.uuid,
|
||||
'description': token.description,
|
||||
'created': raw_datetime(self.rattail_config, token.created),
|
||||
})
|
||||
return tokens
|
||||
|
||||
def get_possible_roles(self):
|
||||
model = self.model
|
||||
|
||||
|
@ -554,6 +640,25 @@ class UserView(PrincipalMasterView):
|
|||
config.add_tailbone_permission(permission_prefix, '{}.edit_roles'.format(permission_prefix),
|
||||
"Edit the Roles to which a {} belongs".format(model_title))
|
||||
|
||||
# manage API tokens
|
||||
config.add_tailbone_permission(permission_prefix,
|
||||
'{}.manage_api_tokens'.format(permission_prefix),
|
||||
"Manage API tokens for any {}".format(model_title))
|
||||
config.add_route('{}.add_api_token'.format(route_prefix),
|
||||
'{}/add-api-token'.format(instance_url_prefix),
|
||||
request_method='POST')
|
||||
config.add_view(cls, attr='add_api_token',
|
||||
route_name='{}.add_api_token'.format(route_prefix),
|
||||
permission='{}.manage_api_tokens'.format(permission_prefix),
|
||||
renderer='json')
|
||||
config.add_route('{}.delete_api_token'.format(route_prefix),
|
||||
'{}/delete-api-token'.format(instance_url_prefix),
|
||||
request_method='POST')
|
||||
config.add_view(cls, attr='delete_api_token',
|
||||
route_name='{}.delete_api_token'.format(route_prefix),
|
||||
permission='{}.manage_api_tokens'.format(permission_prefix),
|
||||
renderer='json')
|
||||
|
||||
# edit preferences for any user
|
||||
config.add_tailbone_permission(permission_prefix,
|
||||
'{}.preferences'.format(permission_prefix),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue