diff --git a/awx/api/serializers.py b/awx/api/serializers.py index c5cb4f7f3a..3d6ba3f52e 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -41,7 +41,7 @@ from awx.main.utils import update_scm_url, get_type_for_model, get_model_for_typ logger = logging.getLogger('awx.api.serializers') # Fields that should be summarized regardless of object type. -DEFAULT_SUMMARY_FIELDS = ('name', 'description')#, 'type') +DEFAULT_SUMMARY_FIELDS = ('name', 'description')#, 'created_by', 'modified_by')#, 'type') # Keys are fields (foreign keys) where, if found on an instance, summary info # should be added to the serialized data. Values are a tuple of field names on @@ -49,7 +49,7 @@ DEFAULT_SUMMARY_FIELDS = ('name', 'description')#, 'type') # the related object). SUMMARIZABLE_FK_FIELDS = { 'organization': DEFAULT_SUMMARY_FIELDS, - 'user': ('username', 'first_name', 'last_name'), + 'user': ('id', 'username', 'first_name', 'last_name'), 'team': DEFAULT_SUMMARY_FIELDS, 'inventory': DEFAULT_SUMMARY_FIELDS + ('has_active_failures', 'total_hosts', @@ -289,6 +289,15 @@ class BaseSerializer(serializers.ModelSerializer): # Can be raised by the reverse accessor for a OneToOneField. except ObjectDoesNotExist: pass + if getattr(obj, 'created_by', None) and obj.created_by.is_active: + summary_fields['created_by'] = SortedDict() + for field in SUMMARIZABLE_FK_FIELDS['user']: + summary_fields['created_by'][field] = getattr(obj.created_by, field) + if getattr(obj, 'modified_by', None) and obj.modified_by.is_active: + summary_fields['modified_by'] = SortedDict() + for field in SUMMARIZABLE_FK_FIELDS['user']: + summary_fields['modified_by'][field] = getattr(obj.modified_by, field) + print summary_fields return summary_fields def get_created(self, obj): diff --git a/awx/api/views.py b/awx/api/views.py index 406e52bfdd..051134389e 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -5,6 +5,7 @@ # Python import datetime import dateutil +import functools import time import re import socket @@ -431,30 +432,32 @@ class DashboardInventoryGraphView(APIView): return Response(dashboard_data) -class UserCreateAPIMixin(object): - """A mixin subclass that ensures that only a superuser is able to create - another superuser. +def disallow_superuser_escalation(cls): + """Decorator that ensures that the post, put, and patch methods on the + class, if they exist, perform a sanity check and disallow superuser + escalation by non-superusers. """ - def post(self, request, pk=None): - self._superuser_sanity_check(request) - return super(UserCreateAPIMixin, self).post(request, pk=pk) + # Create a method decorator that ensures superuser escalation by + # non-superusers is disallowed. + def superuser_lockdown(method): + @functools.wraps(method) + def fx(self, request, *a, **kw): + if not request.user.is_superuser: + if request.DATA.get('is_superuser', False): + raise PermissionDenied('Only superusers may create ' + 'other superusers.') + return method(self, request, *a, **kw) + return fx - # def put(self, request, pk=None): - # self._superuser_sanity_check(request) - # return super(UserCreateAPIMixin, self).put(request, pk=pk) + # Ensure that if post, put, or patch methods exist, that they are decorated + # with the sanity check decorator. + for vuln_method in ('post', 'put', 'patch'): + original_method = getattr(cls, vuln_method, None) + if original_method is not None: + setattr(cls, vuln_method, superuser_lockdown(original_method)) - # def patch(self, request, pk=None): - # self._superuser_sanity_check(request) - # return super(UserCreateAPIMixin, self).patch(request, pk=pk) - - def _superuser_sanity_check(self, request): - """Ensure that if a non-superuser tries to create a superuser, - that the request is rejected. - """ - if not request.user.is_superuser: - if request.DATA.get('is_superuser', False): - raise PermissionDenied('Only superusers may create ' - 'other superusers.') + # Return the class object. + return cls class ScheduleList(ListAPIView): @@ -518,14 +521,16 @@ class OrganizationInventoriesList(SubListAPIView): parent_model = Organization relationship = 'inventories' -class OrganizationUsersList(UserCreateAPIMixin, SubListCreateAPIView): +@disallow_superuser_escalation +class OrganizationUsersList(SubListCreateAPIView): model = User serializer_class = UserSerializer parent_model = Organization relationship = 'users' -class OrganizationAdminsList(UserCreateAPIMixin, SubListCreateAPIView): +@disallow_superuser_escalation +class OrganizationAdminsList(SubListCreateAPIView): model = User serializer_class = UserSerializer @@ -565,7 +570,8 @@ class TeamDetail(RetrieveUpdateDestroyAPIView): model = Team serializer_class = TeamSerializer -class TeamUsersList(UserCreateAPIMixin, SubListCreateAPIView): +@disallow_superuser_escalation +class TeamUsersList(SubListCreateAPIView): model = User serializer_class = UserSerializer @@ -762,7 +768,9 @@ class ProjectUpdateCancel(GenericAPIView): else: return self.http_method_not_allowed(request, *args, **kwargs) -class UserList(UserCreateAPIMixin, ListCreateAPIView): + +@disallow_superuser_escalation +class UserList(ListCreateAPIView): model = User serializer_class = UserSerializer @@ -841,6 +849,7 @@ class UserActivityStreamList(SubListAPIView): return qs.filter(Q(actor=parent) | Q(user__in=[parent])) + class UserDetail(RetrieveUpdateDestroyAPIView): model = User @@ -1467,6 +1476,7 @@ class JobTemplateLaunch(GenericAPIView): data['passwords_needed_to_start'] = obj.passwords_needed_to_start data['ask_variables_on_launch'] = obj.ask_variables_on_launch data['variables_needed_to_start'] = obj.variables_needed_to_start + data['credential_needed_to_start'] = obj.credential is None data['survey_enabled'] = obj.survey_enabled return Response(data) diff --git a/awx/main/access.py b/awx/main/access.py index 4eaa4ad7f5..0c867426f7 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -826,41 +826,56 @@ class JobTemplateAccess(BaseAccess): org_admin_qs = base_qs.filter( project__organizations__admins__in=[self.user] ) - allowed = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY] - perm_qs = base_qs.filter( + allowed = [PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY] + allowed_deploy = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY] + allowed_check = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK] + + # perm_qs = base_qs.filter( + # Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]), + # Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]), + # inventory__permissions__permission_type__in=allowed, + # project__permissions__permission_type__in=allowed, + # inventory__permissions__active=True, + # project__permissions__active=True, + # inventory__permissions__pk=F('project__permissions__pk'), + # ) + + perm_deploy_qs = base_qs.filter( Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]), Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]), - inventory__permissions__permission_type__in=allowed, - project__permissions__permission_type__in=allowed, + job_type=PERM_INVENTORY_DEPLOY, + inventory__permissions__permission_type__in=allowed_deploy, + project__permissions__permission_type__in=allowed_deploy, inventory__permissions__active=True, project__permissions__active=True, inventory__permissions__pk=F('project__permissions__pk'), ) + + perm_check_qs = base_qs.filter( + Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]), + Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]), + job_type=PERM_INVENTORY_CHECK, + inventory__permissions__permission_type__in=allowed_check, + project__permissions__permission_type__in=allowed_check, + inventory__permissions__active=True, + project__permissions__active=True, + inventory__permissions__pk=F('project__permissions__pk'), + ) + # FIXME: I *think* this should work... needs more testing. - return org_admin_qs | perm_qs + return org_admin_qs | perm_deploy_qs | perm_check_qs def can_read(self, obj): # you can only see the job templates that you have permission to launch. - data = { - 'job_type': obj.job_type, - } - if obj.inventory and obj.inventory.pk: - data['inventory'] = obj.inventory.pk - if obj.project and obj.project.pk: - data['project'] = obj.project.pk - if obj.credential: - data['credential'] = obj.credential.pk - if obj.cloud_credential: - data['cloud_credential'] = obj.cloud_credential.pk - return self.can_add(data) + return self.can_start(obj) def can_add(self, data): ''' a user can create a job template if they are a superuser, an org admin of any org that the project is a member, or if they have user or team based permissions tying the project to the inventory source for the - given action. users who are able to create deploy jobs can also make - check (dry run) jobs. + given action as well as the 'create' deploy permission. + Users who are able to create deploy jobs can also run normal and check (dry run) jobs. ''' if not data or '_method' in data: # So the browseable API will work? return True @@ -950,29 +965,32 @@ class JobTemplateAccess(BaseAccess): if obj.inventory is None or obj.project is None: return False # If the user has admin access to the project they can start a job - if self.user.can_access(Project, 'admin', obj.project): + if self.user.can_access(Project, 'admin', obj.project, None): return True # Otherwise check for explicitly granted permissions permission_qs = Permission.objects.filter( Q(user=self.user) | Q(team__users__in=[self.user]), - inventory=inventory, - project=project, + inventory=obj.inventory, + project=obj.project, permission_type__in=[PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY], ) + has_perm = False for perm in permission_qs: # If you have job template create permission that implies both CHECK and DEPLOY # If you have DEPLOY permissions you can run both CHECK and DEPLOY - if perm.permission_type in [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY]: + if perm.permission_type in [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY] and \ + obj.job_type == PERM_INVENTORY_DEPLOY: has_perm = True # If you only have CHECK permission then you can only run CHECK - if perm.permission_type == PERM_INVENTORY_CHECK and perm.permission_type == PERM_INVENTORY_CHECK: + if perm.permission_type in [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK] and \ + obj.job_type == PERM_INVENTORY_CHECK: has_perm = True dep_access = self.user.can_access(Inventory, 'read', obj.inventory) and \ self.user.can_access(Project, 'read', obj.project) - return self.can_read(obj) and dep_access and has_perm + return dep_access and has_perm def can_change(self, obj, data): return self.can_read(obj) and self.can_add(data) @@ -998,17 +1016,44 @@ class JobAccess(BaseAccess): project__organizations__admins__in=[self.user] ) allowed = [PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY] - perm_qs = base_qs.filter( + + allowed_deploy = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY] + allowed_check = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK] + + # perm_qs = base_qs.filter( + # Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]), + # Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]), + # inventory__permissions__permission_type__in=allowed, + # project__permissions__permission_type__in=allowed, + # inventory__permissions__active=True, + # project__permissions__active=True, + # inventory__permissions__pk=F('project__permissions__pk'), + # ) + + perm_deploy_qs = base_qs.filter( Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]), Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]), - inventory__permissions__permission_type__in=allowed, - project__permissions__permission_type__in=allowed, + job_type=PERM_INVENTORY_DEPLOY, + inventory__permissions__permission_type__in=allowed_deploy, + project__permissions__permission_type__in=allowed_deploy, inventory__permissions__active=True, project__permissions__active=True, inventory__permissions__pk=F('project__permissions__pk'), ) + + perm_check_qs = base_qs.filter( + Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]), + Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]), + job_type=PERM_INVENTORY_CHECK, + inventory__permissions__permission_type__in=allowed_check, + project__permissions__permission_type__in=allowed_check, + inventory__permissions__active=True, + project__permissions__active=True, + inventory__permissions__pk=F('project__permissions__pk'), + ) + # FIXME: I *think* this should work... needs more testing. - return org_admin_qs | perm_qs + return org_admin_qs | perm_deploy_qs | perm_check_qs def can_add(self, data): if not data or '_method' in data: # So the browseable API will work? diff --git a/awx/main/tasks.py b/awx/main/tasks.py index be6f37cd90..8c71428f3b 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -339,12 +339,13 @@ class BaseTask(Task): - /etc/tower (to prevent obtaining db info or secret key) - /var/lib/awx (except for current project) - /var/log/tower + - /var/log/supervisor - /tmp (except for own tmp files) ''' new_args = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '-r', '/'] hide_paths = ['/etc/tower', '/var/lib/awx', '/var/log/tower', - tempfile.gettempdir(), settings.PROJECTS_ROOT, - settings.JOBOUTPUT_ROOT] + '/var/log/supervisor', tempfile.gettempdir(), + settings.PROJECTS_ROOT, settings.JOBOUTPUT_ROOT] hide_paths.extend(getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or []) for path in sorted(set(hide_paths)): if not os.path.exists(path): @@ -1052,7 +1053,7 @@ class RunInventoryUpdate(BaseTask): pass elif inventory_update.source == 'custom': for env_k in inventory_update.source_vars_dict: - if str(env_k) not in os.environ: + if str(env_k) not in os.environ and str(env_k) not in settings.INV_ENV_VARIABLE_BLACKLIST: env[str(env_k)] = unicode(inventory_update.source_vars_dict[env_k]) return env diff --git a/awx/main/tests/tasks.py b/awx/main/tests/tasks.py index 682fd12933..93a6bdd97f 100644 --- a/awx/main/tests/tasks.py +++ b/awx/main/tests/tasks.py @@ -3,6 +3,7 @@ # Python from distutils.version import StrictVersion as Version +import glob import json import os import shutil @@ -176,6 +177,15 @@ TEST_PROOT_PLAYBOOK = ''' assert: that: - "not temp_stat.stat.exists" + - name: check for supervisor log path + stat: path={{ supervisor_log_path }} + register: supervisor_log_stat + when: supervisor_log_path is defined + - name: check that supervisor log path was not found + assert: + that: + - "not supervisor_log_stat.stat.exists" + when: supervisor_log_path is defined - name: try to run a tower-manage command command: tower-manage validate ignore_errors: true @@ -1353,6 +1363,11 @@ class RunJobTest(BaseCeleryTest): # Create a temp directory that should not be visible to the playbook. temp_path = tempfile.mkdtemp() self._temp_paths.append(temp_path) + # Find a file in supervisor logs that should not be visible. + try: + supervisor_log_path = glob.glob('/var/log/supervisor/*')[0] + except IndexError: + supervisor_log_path = None # Create our test project and job template. self.create_test_project(TEST_PROOT_PLAYBOOK) project_path = self.project.local_path @@ -1364,6 +1379,8 @@ class RunJobTest(BaseCeleryTest): 'other_project_path': other_project_path, 'temp_path': temp_path, } + if supervisor_log_path: + extra_vars['supervisor_log_path'] = supervisor_log_path job = self.create_test_job(job_template=job_template, verbosity=3, extra_vars=json.dumps(extra_vars)) self.assertEqual(job.status, 'new') diff --git a/awx/plugins/inventory/vmware.py b/awx/plugins/inventory/vmware.py index 85b38739b4..d72bed09b6 100755 --- a/awx/plugins/inventory/vmware.py +++ b/awx/plugins/inventory/vmware.py @@ -193,10 +193,13 @@ class VMwareInventory(object): host_info = { 'name': host.name, 'tag': host.tag, - 'datastores': self._get_obj_info(host.datastore, depth=0), - 'networks': self._get_obj_info(host.network, depth=0), - 'vms': self._get_obj_info(host.vm, depth=0), } + for attr in ('datastore', 'network', 'vm'): + try: + value = getattr(host, attr) + host_info['%ss' % attr] = self._get_obj_info(value, depth=0) + except AttributeError: + host_info['%ss' % attr] = [] for k, v in self._get_obj_info(host.summary, depth=0).items(): if isinstance(v, collections.MutableMapping): for k2, v2 in v.items(): @@ -219,11 +222,21 @@ class VMwareInventory(object): vm_info = { 'name': vm.name, 'tag': vm.tag, - 'datastores': self._get_obj_info(vm.datastore, depth=0), - 'networks': self._get_obj_info(vm.network, depth=0), - 'resourcePool': self._get_obj_info(vm.resourcePool, depth=0), - 'guestState': vm.guest.guestState, } + for attr in ('datastore', 'network'): + try: + value = getattr(vm, attr) + vm_info['%ss' % attr] = self._get_obj_info(value, depth=0) + except AttributeError: + vm_info['%ss' % attr] = [] + try: + vm_info['resourcePool'] = self._get_obj_info(vm.resourcePool, depth=0) + except AttributeError: + vm_info['resourcePool'] = '' + try: + vm_info['guestState'] = vm.guest.guestState + except AttributeError: + vm_info['guestState'] = '' for k, v in self._get_obj_info(vm.summary, depth=0).items(): if isinstance(v, collections.MutableMapping): for k2, v2 in v.items(): diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 7e5cf1b64a..1fbd7c27f3 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -351,6 +351,8 @@ RAX_GROUP_FILTER = r'^(?!instance-.+).+$' RAX_HOST_FILTER = r'^.+$' RAX_EXCLUDE_EMPTY_GROUPS = True +INV_ENV_VARIABLE_BLACKLIST = ("HOME", "_") + # ---------------- # -- Amazon EC2 -- # ---------------- diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 1d6390c11b..ec889c0302 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -649,6 +649,10 @@ angular.module('Tower', [ $AnsibleConfig = Store('AnsibleConfig'); } + //the authorization controller redirects to the home page automatcially if there is no last path defined. in order to override + // this, set the last path to /portal for instances where portal is visited for the first time. + $rootScope.lastPath = ($location.path() === "/portal") ? 'portal' : undefined; + LoadConfig(); } ]); diff --git a/awx/ui/static/js/config.js b/awx/ui/static/js/config.js index ce064c6eba..abed710242 100644 --- a/awx/ui/static/js/config.js +++ b/awx/ui/static/js/config.js @@ -19,7 +19,7 @@ tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips - debug_mode: true, // Enable console logging messages + debug_mode: false, // Enable console logging messages password_strength: 45, // User password strength. Integer between 0 and 100, 100 being impossibly strong. // This value controls progress bar colors: diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index 7f95a68d0b..cbafb57b89 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -77,10 +77,9 @@ function JobsListController ($rootScope, $log, $scope, $compile, $routeParams, C case 'pending': case 'waiting': queued_scope.search('queued_job'); - break; - case 'successful': completed_scope.search('completed_job'); break; + case 'successful': case 'failed': case 'error': case 'canceled': diff --git a/awx/ui/static/js/controllers/Portal.js b/awx/ui/static/js/controllers/Portal.js index c936f7be4a..d12f9e1c8f 100644 --- a/awx/ui/static/js/controllers/Portal.js +++ b/awx/ui/static/js/controllers/Portal.js @@ -79,7 +79,6 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location, searchSize: 'col-lg-6 col-md-6' }); - $rootScope.flashMessage = null; SearchInit({ scope: $scope, @@ -120,49 +119,11 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location, $('.list-well:eq(1)').css('margin-top' , '0px'); }); - // function processEvent(event) { - // switch(event.status) { - // case 'running': - // jobs_scope.search('running_job'); - // jobs_scope.search('queued_job'); - - // break; - // case 'new': - // case 'pending': - // case 'waiting': - // jobs_scope.search('queued_job'); - - // break; - // case 'successful': - // jobs_scope.search('completed_job'); - // case 'failed': - // case 'error': - // case 'canceled': - // jobs_scope.search('completed_job'); - // jobs_scope.search('running_job'); - // jobs_scope.search('queued_job'); - // } - // } - if ($rootScope.removeJobStatusChange) { $rootScope.removeJobStatusChange(); } $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange', function() { - jobs_scope.refreshJobs(); - // if(data.status==='pending'){ - // // $scope.refresh(); - // $('#portal-jobs').empty(); - // // $rootScope.flashMessage = null; - // PortalJobsWidget({ - // scope: $scope, - // target: 'portal-jobs', - // searchSize: 'col-lg-6 col-md-6' - // }); - // } - - - //x`processEvent(data); - + jobs_scope.search('portal_job'); //processEvent(event); }); $scope.submitJob = function (id) { diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 4422cad7fc..f2817a833e 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -53,7 +53,6 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential $('#password-modal').dialog('close'); } scope.$emit(callback, data); - scope.$destroy(); }) .error(function(data, status) { ProcessErrors(scope, data, status, null, { hdr: 'Error!', @@ -241,7 +240,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi html += "\n"; html += " " + field.label + "\n"; html += "\n"; - // html+= "Job Templates "; - // html += "\n"; - // html += "
\n"; html += "
\n"; html += "\n"; //list html += "
\n"; //active-jobs-tab - // html += "
\n"; - // html += "
\n"; // jobs-list-container html += "\n"; e = angular.element(document.getElementById(target)); @@ -71,44 +58,17 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities']) if (PortalJobsList.fields.type) { PortalJobsList.fields.type.searchOptions = scope.type_choices; } + user = scope.$parent.current_user.id; LoadJobsScope({ parent_scope: scope, scope: jobs_scope, list: PortalJobsList, id: 'active-jobs', - url: GetBasePath('unified_jobs') + '?status__in=running,completed,failed,successful,error,canceled', + url: GetBasePath('jobs')+'?created_by='+user, pageSize: max_rows, spinner: true }); - // completed_scope.showJobType = true; - // LoadJobsScope({ - // parent_scope: scope, - // scope: completed_scope, - // list: PortalJobsList, - // id: 'active-jobs', - // url: GetBasePath('unified_jobs') + '?or__status=successful&or__status=failed&or__status=error&or__status=canceled', - // // searchParams: search_params, - // pageSize: max_rows - // }); - - // LoadJobsScope({ - // parent_scope: scope, - // scope: running_scope, - // list: PortalJobsList, - // id: 'active-jobs', - // url: GetBasePath('unified_jobs') + '?status=running', - // pageSize: max_rows - // }); - - // LoadJobsScope({ - // parent_scope: scope, - // scope: queued_scope, - // list: PortalJobsList, - // id: 'active-jobs', - // url: GetBasePath('unified_jobs') + '?or__status=pending&or__status=waiting&or__status=new', - // pageSize: max_rows - // }); $(window).resize(_.debounce(function() { resizePortalJobsWidget(); diff --git a/awx/ui/static/lib/ansible/AuthService.js b/awx/ui/static/lib/ansible/AuthService.js index c782292e8a..6da3ec3297 100644 --- a/awx/ui/static/lib/ansible/AuthService.js +++ b/awx/ui/static/lib/ansible/AuthService.js @@ -64,7 +64,16 @@ angular.module('AuthService', ['ngCookies', 'Utilities']) //$rootScope.$destroy(); $cookieStore.remove('token_expires'); $cookieStore.remove('current_user'); - $cookieStore.remove('lastPath'); + + if($cookieStore.get('lastPath')==='/portal'){ + $cookieStore.put( 'lastPath', '/portal'); + $rootScope.lastPath = '/portal'; + } + else { + $cookieStore.remove('lastPath'); + $rootScope.lastPath = '/home'; + } + $cookieStore.remove('token'); $cookieStore.put('userLoggedIn', false); $cookieStore.put('sessionExpired', false); @@ -75,7 +84,6 @@ angular.module('AuthService', ['ngCookies', 'Utilities']) $rootScope.sessionExpired = false; $rootScope.token = null; $rootScope.token_expires = null; - $rootScope.lastPath = '/home'; $rootScope.login_username = null; $rootScope.login_password = null; }, diff --git a/awx/ui/static/lib/ansible/Socket.js b/awx/ui/static/lib/ansible/Socket.js index 9dc7c9cd92..ccbd4ec150 100644 --- a/awx/ui/static/lib/ansible/Socket.js +++ b/awx/ui/static/lib/ansible/Socket.js @@ -28,7 +28,6 @@ angular.module('SocketIO', ['AuthService', 'Utilities']) endpoint = params.endpoint, protocol = $location.protocol(), config, socketPort, - // handshakeData, url; // Since some pages are opened in a new tab, we might get here before AnsibleConfig is available.