def _check_for_user_lockout(original_object): """ Only to be called when the current user is known to have PERMIT_ADMIN_USERS permission, checks that the current user hasn't locked themselves out from user administration. Also checks that the admin user's administration permission has not been accidentally revoked. If a lockout has occurred, the supplied original object is re-saved and a ParameterError is raised. """ user_ids = [get_session_user_id(), 1] for user_id in user_ids: db_user = data_engine.get_user(user_id=user_id) if db_user: try: # Require user administration if not permissions_engine.is_permitted( SystemPermissions.PERMIT_ADMIN_USERS, db_user ): raise ParameterError() # For the admin user, also require permissions administration if user_id == 1 and not permissions_engine.is_permitted( SystemPermissions.PERMIT_ADMIN_PERMISSIONS, db_user ): raise ParameterError() except ParameterError: # Roll back permissions data_engine.save_object(original_object) permissions_engine.reset() # Raise API error who = 'the \'admin\' user' if user_id == 1 else 'you' raise ParameterError( 'This change would lock %s out of administration' % who )
def post(self, group_id): params = self._get_validated_object_parameters(request.form) group = data_engine.get_group(group_id=group_id, load_users=True) if group is None: raise DoesNotExistError(str(group_id)) # Check permissions! The current user must have user admin to be here. # But if they don't also have permissions admin or superuser then we # must block the change if the new group would grant one of the same. if group.permissions.admin_permissions or group.permissions.admin_all: if not permissions_engine.is_permitted( SystemPermissions.PERMIT_ADMIN_PERMISSIONS, get_session_user()): raise SecurityError( 'You cannot add users to a group that ' + 'grants permissions administration, because you do not ' + 'have permissions administration access yourself.') user = data_engine.get_user(user_id=params['user_id']) if user is not None: if user not in group.users: group.users.append(user) data_engine.save_object(group) reset_user_sessions(user) permissions_engine.reset() return make_api_success_response()
def _check_for_user_lockout(original_object): """ Only to be called when the current user is known to have PERMIT_ADMIN_USERS permission, checks that the current user hasn't locked themselves out from user administration. Also checks that the admin user's administration permission has not been accidentally revoked. If a lockout has occurred, the supplied original object is re-saved and a ParameterError is raised. """ user_ids = [get_session_user_id(), 1] for user_id in user_ids: db_user = data_engine.get_user(user_id=user_id) if db_user: try: # Require user administration if not permissions_engine.is_permitted( SystemPermissions.PERMIT_ADMIN_USERS, db_user): raise ParameterError() # For the admin user, also require permissions administration if user_id == 1 and not permissions_engine.is_permitted( SystemPermissions.PERMIT_ADMIN_PERMISSIONS, db_user): raise ParameterError() except ParameterError: # Roll back permissions data_engine.save_object(original_object) permissions_engine.reset() # Raise API error who = 'the \'admin\' user' if user_id == 1 else 'you' raise ParameterError( 'This change would lock %s out of administration' % who)
def post(self, group_id): params = self._get_validated_object_parameters(request.form) group = data_engine.get_group(group_id=group_id, load_users=True) if group is None: raise DoesNotExistError(str(group_id)) # Check permissions! The current user must have user admin to be here. # But if they don't also have permissions admin or superuser then we # must block the change if the new group would grant one of the same. if group.permissions.admin_permissions or group.permissions.admin_all: if not permissions_engine.is_permitted( SystemPermissions.PERMIT_ADMIN_PERMISSIONS, get_session_user() ): raise SecurityError( 'You cannot add users to a group that ' + 'grants permissions administration, because you do not ' + 'have permissions administration access yourself.' ) user = data_engine.get_user(user_id=params['user_id']) if user is not None: if user not in group.users: group.users.append(user) data_engine.save_object(group) permissions_engine.reset() return make_api_success_response()
def test_task_server(self): # Create some stats t_now = datetime.utcnow() dm.save_object(SystemStats( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, t_now - timedelta(minutes=5), t_now )) # We should now have stats sys_stats = dm.search_system_stats(t_now - timedelta(minutes=60), t_now) self.assertGreater(len(sys_stats), 0) # Check current task list entries tasks = dm.list_objects(Task, order_field=Task.id) task_list_len = len(tasks) # Post a background task to purge the stats KEEP_SECS = 10 task_obj = tm.add_task( None, 'Purge system statistics', 'purge_system_stats', {'before_time': t_now}, Task.PRIORITY_NORMAL, 'info', 'error', KEEP_SECS ) self.assertIsNotNone(task_obj) # Check it really got added tasks = dm.list_objects(Task, order_field=Task.id) self.assertEqual(len(tasks), task_list_len + 1) task_list_len = len(tasks) # Post it again, make sure there is no dupe added dupe_task_obj = tm.add_task( None, 'Purge system statistics', 'purge_system_stats', {'before_time': t_now}, Task.PRIORITY_NORMAL, 'info', 'error', KEEP_SECS ) self.assertIsNone(dupe_task_obj) # Check it really didn't get re-added tasks = dm.list_objects(Task, order_field=Task.id) self.assertEqual(len(tasks), task_list_len) task = tasks[-1] self.assertEqual(task.id, task_obj.id) # Wait for task completion tm.wait_for_task(task_obj.id, 20) # We should now have no stats t_now = datetime.utcnow() sys_stats = dm.search_system_stats(t_now - timedelta(minutes=60), t_now) self.assertEqual(len(sys_stats), 0) # The completed task should only be removed after the delay we specified task = dm.get_object(Task, task_obj.id) self.assertIsNotNone(task) self.assertEqual(task.status, Task.STATUS_COMPLETE) # Wait for keep time + task server's poll time time.sleep(KEEP_SECS + 10) # Should now be gone task = dm.get_object(Task, task_obj.id) self.assertIsNone(task)
def put(self, permission_id): params = self._get_validated_object_parameters(request.form) fp = data_engine.get_object(FolderPermission, permission_id) if fp is None: raise DoesNotExistError(str(permission_id)) fp.access = params['access'] data_engine.save_object(fp) permissions_engine.reset_folder_permissions() return make_api_success_response(object_to_dict(fp))
def put(self, permission_id): params = self._get_validated_object_parameters(request.form) fp = data_engine.get_object(FolderPermission, permission_id) if fp is None: raise DoesNotExistError(str(permission_id)) fp.access = params['access'] data_engine.save_object(fp) permissions_engine.reset() return make_api_success_response(object_to_dict(fp))
def put(self, property_id): params = self._get_validated_object_parameters(request.form) db_prop = data_engine.get_object(Property, property_id) if db_prop is None: raise DoesNotExistError(str(property_id)) db_prop.value = params['value'] data_engine.save_object(db_prop) if property_id == Property.DEFAULT_TEMPLATE: image_engine.reset_templates() return make_api_success_response(object_to_dict(db_prop))
def put(self, image_id): params = self._get_validated_object_parameters(request.form) # Get image and update it db_img = data_engine.get_image(image_id=image_id) if not db_img: raise DoesNotExistError(str(image_id)) # Require edit permission or file admin permissions_engine.ensure_folder_permitted( db_img.folder, FolderPermission.ACCESS_EDIT, get_session_user() ) old_title = db_img.title old_description = db_img.description db_img.title = params['title'] db_img.description = params['description'] data_engine.save_object(db_img) # Get text changes. Max info length = # 100 + 200 + len('()' + '()' + 'Title: ' + ' / ' + 'Description: ') ==> 327 title_diff = get_string_changes(old_title, params['title'], char_limit=100).strip() if not title_diff: # Try for deletions from title title_diff = get_string_changes(params['title'], old_title, char_limit=100).strip() if title_diff: title_diff = '(' + title_diff + ')' desc_diff = get_string_changes( old_description, params['description'], char_limit=200 ).strip() if not desc_diff: # Try for deletions from description desc_diff = get_string_changes( params['description'], old_description, char_limit=200 ).strip() if desc_diff: desc_diff = '(' + desc_diff + ')' info = '' if title_diff: info += 'Title: ' + title_diff if info and desc_diff: info += ' / ' if desc_diff: info += 'Description: ' + desc_diff # Add change history data_engine.add_image_history( db_img, get_session_user(), ImageHistory.ACTION_EDITED, info ) return make_api_success_response(object_to_dict(db_img))
def test_task_server(self): # Create some stats t_now = datetime.utcnow() dm.save_object( SystemStats(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, t_now - timedelta(minutes=5), t_now)) # We should now have stats sys_stats = dm.search_system_stats(t_now - timedelta(minutes=60), t_now) self.assertGreater(len(sys_stats), 0) # Check current task list entries tasks = dm.list_objects(Task, order_field=Task.id) task_list_len = len(tasks) # Post a background task to purge the stats KEEP_SECS = 10 task_obj = tm.add_task(None, 'Purge system statistics', 'purge_system_stats', {'before_time': t_now}, Task.PRIORITY_NORMAL, 'info', 'error', KEEP_SECS) self.assertIsNotNone(task_obj) # Check it really got added tasks = dm.list_objects(Task, order_field=Task.id) self.assertEqual(len(tasks), task_list_len + 1) task_list_len = len(tasks) # Post it again, make sure there is no dupe added dupe_task_obj = tm.add_task(None, 'Purge system statistics', 'purge_system_stats', {'before_time': t_now}, Task.PRIORITY_NORMAL, 'info', 'error', KEEP_SECS) self.assertIsNone(dupe_task_obj) # Check it really didn't get re-added tasks = dm.list_objects(Task, order_field=Task.id) self.assertEqual(len(tasks), task_list_len) task = tasks[-1] self.assertEqual(task.id, task_obj.id) # Wait for task completion tm.wait_for_task(task_obj.id, 10) # We should now have no stats t_now = datetime.utcnow() sys_stats = dm.search_system_stats(t_now - timedelta(minutes=60), t_now) self.assertEqual(len(sys_stats), 0) # The completed task should only be removed after the delay we specified task = dm.get_object(Task, task_obj.id) self.assertIsNotNone(task) self.assertEqual(task.status, Task.STATUS_COMPLETE) # Wait for keep time + task server's poll time time.sleep(KEEP_SECS + 10) # Should now be gone task = dm.get_object(Task, task_obj.id) self.assertIsNone(task)
def put(self, image_id): params = self._get_validated_object_parameters(request.form) # Get image and update it db_img = data_engine.get_image(image_id=image_id) if not db_img: raise DoesNotExistError(str(image_id)) # Require edit permission or file admin permissions_engine.ensure_folder_permitted( db_img.folder, FolderPermission.ACCESS_EDIT, get_session_user()) old_title = db_img.title old_description = db_img.description db_img.title = params['title'] db_img.description = params['description'] data_engine.save_object(db_img) # Get text changes. Max info length = # 100 + 200 + len('()' + '()' + 'Title: ' + ' / ' + 'Description: ') ==> 327 title_diff = get_string_changes(old_title, params['title'], char_limit=100).strip() if not title_diff: # Try for deletions from title title_diff = get_string_changes(params['title'], old_title, char_limit=100).strip() if title_diff: title_diff = '(' + title_diff + ')' desc_diff = get_string_changes(old_description, params['description'], char_limit=200).strip() if not desc_diff: # Try for deletions from description desc_diff = get_string_changes(params['description'], old_description, char_limit=200).strip() if desc_diff: desc_diff = '(' + desc_diff + ')' info = '' if title_diff: info += 'Title: ' + title_diff if info and desc_diff: info += ' / ' if desc_diff: info += 'Description: ' + desc_diff # Add change history data_engine.add_image_history(db_img, get_session_user(), ImageHistory.ACTION_EDITED, info) return make_api_success_response( object_to_dict(_prep_image_object(db_img)))
def put(self, template_id): permissions_engine.ensure_permitted( SystemPermissions.PERMIT_SUPER_USER, get_session_user()) params = self._get_validated_object_parameters(request.form) template = data_engine.get_image_template(template_id) if template is None: raise DoesNotExistError(str(template_id)) template.name = params['name'] template.description = params['description'] template.template = params['template'] data_engine.save_object(template) image_engine.reset_templates() return self.get(template.id)
def put(self, folio_id): db_session = data_engine.db_get_session() try: # Get portfolio folio = data_engine.get_portfolio(folio_id, _db_session=db_session) if folio is None: raise DoesNotExistError(str(folio_id)) # Check permissions permissions_engine.ensure_portfolio_permitted( folio, FolioPermission.ACCESS_EDIT, get_session_user()) # Update the object params = self._get_validated_object_parameters(request.form) permissions_changed = self._set_permissions( folio, params, db_session) changes = [] if params['human_id'] != folio.human_id: changes.append('short URL changed') if params['name'] != folio.name: changes.append('name changed') if params['description'] != folio.description: changes.append('description changed') if permissions_changed: changes.append('permissions changed') folio.human_id = params['human_id'] or Folio.create_human_id() folio.name = params['name'] folio.description = params['description'] # Note: folio.last_updated is only for image changes # (to know when to invalidate the exported zips) data_engine.add_portfolio_history(folio, get_session_user(), FolioHistory.ACTION_EDITED, ', '.join(changes).capitalize(), _db_session=db_session, _commit=False) data_engine.save_object( folio, _db_session=db_session, _commit=True # fail here if human_id not unique ) if permissions_changed: permissions_engine.reset_portfolio_permissions() # Return a clean object the same as for get(id) folio = data_engine.get_portfolio(folio.id, load_images=True, load_history=True) folio = _prep_folio_object(folio) return make_api_success_response( object_to_dict(folio, _omit_fields)) finally: db_session.close()
def apply_user(params): from imageserver.flask_app import data_engine from imageserver.models import User from imageserver.errors import DBError try: existing_user = data_engine.get_user(username=params.username) if params.mode == Parameters.MODE_ADD: if existing_user: if existing_user.status == User.STATUS_DELETED: raise ValueError('A deleted user record for this username already exists') else: raise ValueError('This username already exists') else: data_engine.create_user(User( params.firstname, params.lastname, params.email, params.username, params.password, User.AUTH_TYPE_PASSWORD, False, User.STATUS_ACTIVE )) log('User created') elif params.mode == Parameters.MODE_UPDATE: if not existing_user: raise ValueError('The username was not found') if existing_user.status == User.STATUS_DELETED: raise ValueError('This user record is deleted') existing_user.first_name = params.firstname existing_user.last_name = params.lastname existing_user.email = params.email existing_user.set_password(params.password) data_engine.save_object(existing_user) log('User updated') else: if not existing_user: raise ValueError('The username was not found') data_engine.delete_user(existing_user) log('User deleted') return RETURN_OK except ValueError as e: error(str(e)) return RETURN_BAD_PARAMS except DBError as e: error(str(e)) return RETURN_DB_ERROR
def delete(self, group_id, user_id): group = data_engine.get_group(group_id=group_id, load_users=True) if group is None: raise DoesNotExistError(str(group_id)) # Back up the object in case we need to restore it backup_group = copy.deepcopy(group) # Update group membership for idx, member in enumerate(group.users): if member.id == user_id: del group.users[idx] data_engine.save_object(group) permissions_engine.reset() _check_for_user_lockout(backup_group) break return make_api_success_response()
def post(self): params = self._get_validated_object_parameters(request.form) db_session = data_engine.db_get_session() db_commit = False try: db_group = data_engine.get_group(params['group_id'], _db_session=db_session) if db_group is None: raise DoesNotExistError(str(params['group_id'])) db_folder = data_engine.get_folder(params['folder_id'], _db_session=db_session) if db_folder is None: raise DoesNotExistError(str(params['folder_id'])) # This commits (needed for refresh to get the new ID) fp = FolderPermission(db_folder, db_group, params['access']) fp = data_engine.save_object(fp, refresh=True, _db_session=db_session, _commit=True) db_commit = True return make_api_success_response(object_to_dict(fp)) finally: try: if db_commit: db_session.commit() permissions_engine.reset_folder_permissions() else: db_session.rollback() finally: db_session.close()
def delete(self, group_id, user_id): group = data_engine.get_group(group_id=group_id, load_users=True) if group is None: raise DoesNotExistError(str(group_id)) # Back up the object in case we need to restore it backup_group = copy.deepcopy(group) # Update group membership for idx, member in enumerate(group.users): if member.id == user_id: del group.users[idx] data_engine.save_object(group) reset_user_sessions(member) permissions_engine.reset() _check_for_user_lockout(backup_group) break return make_api_success_response()
def post(self): params = self._get_validated_object_parameters(request.form) db_session = data_engine.db_get_session() db_commit = False try: db_group = data_engine.get_group(params['group_id'], _db_session=db_session) if db_group is None: raise DoesNotExistError(str(params['group_id'])) db_folder = data_engine.get_folder(params['folder_id'], _db_session=db_session) if db_folder is None: raise DoesNotExistError(str(params['folder_id'])) # This commits (needed for refresh to get the new ID) fp = FolderPermission(db_folder, db_group, params['access']) fp = data_engine.save_object( fp, refresh=True, _db_session=db_session, _commit=True ) db_commit = True return make_api_success_response(object_to_dict(fp)) finally: try: if db_commit: db_session.commit() permissions_engine.reset() else: db_session.rollback() finally: db_session.close()
def post(self, folio_id): db_session = data_engine.db_get_session() try: # Get the portfolio folio = data_engine.get_portfolio(folio_id, _db_session=db_session) if folio is None: raise DoesNotExistError(str(folio_id)) # Check permissions permissions_engine.ensure_portfolio_permitted( folio, FolioPermission.ACCESS_EDIT, get_session_user()) # Block the export now if it would create an empty zip file if len(folio.images) == 0: raise ParameterError( 'this portfolio is empty and cannot be published') # Create a folio-export record and start the export as a background task params = self._get_validated_object_parameters(request.form) folio_export = FolioExport(folio, params['description'], params['originals'], params['image_parameters'], params['expiry_time']) data_engine.add_portfolio_history(folio, get_session_user(), FolioHistory.ACTION_PUBLISHED, folio_export.describe(True), _db_session=db_session, _commit=False) folio_export = data_engine.save_object(folio_export, refresh=True, _db_session=db_session, _commit=True) export_task = task_engine.add_task( get_session_user(), 'Export portfolio %d / export %d' % (folio.id, folio_export.id), 'export_portfolio', { 'export_id': folio_export.id, 'ignore_errors': False }, Task.PRIORITY_NORMAL, 'info', 'error', 60) # Update and return the folio-export record with the task ID folio_export.task_id = export_task.id data_engine.save_object(folio_export, _db_session=db_session, _commit=True) return make_api_success_response(object_to_dict( _prep_folioexport_object(folio, folio_export), _omit_fields + ['portfolio']), task_accepted=True) finally: db_session.close()
def post(self): permissions_engine.ensure_permitted( SystemPermissions.PERMIT_SUPER_USER, get_session_user()) params = self._get_validated_object_parameters(request.form) template = ImageTemplate(params['name'], params['description'], params['template']) template = data_engine.save_object(template, refresh=True) image_engine.reset_templates() return self.get(template.id)
def put(self, user_id): params = self._get_validated_object_parameters(request.form, False) user = data_engine.get_user(user_id=user_id) if user is None: raise DoesNotExistError(str(user_id)) user.first_name = params['first_name'] user.last_name = params['last_name'] user.email = params['email'] user.auth_type = params['auth_type'] user.allow_api = params['allow_api'] # Don't update the status field with this method # Update username only if non-LDAP if user.auth_type != User.AUTH_TYPE_LDAP: user.username = params['username'] # Update password only if non-LDAP and a new one was passed in if user.auth_type != User.AUTH_TYPE_LDAP and params['password']: user.set_password(params['password']) data_engine.save_object(user) # Reset session caches reset_user_sessions(user) return make_api_success_response(object_to_dict(user))
def put(self, group_id): params = self._get_validated_object_parameters(request.form) group = data_engine.get_group(group_id=group_id, load_users=True) if group is None: raise DoesNotExistError(str(group_id)) # Back up the object in case we need to restore it backup_group = copy.deepcopy(group) # Update group group.description = params['description'] if group.group_type != Group.GROUP_TYPE_SYSTEM: group.group_type = params['group_type'] if group.group_type == Group.GROUP_TYPE_LOCAL: group.name = params['name'] permissions_changed = self._set_permissions(group, params) data_engine.save_object(group) # Reset permissions and session caches if permissions_changed: reset_user_sessions(group.users) permissions_engine.reset() _check_for_user_lockout(backup_group) return make_api_success_response(object_to_dict(group))
def put(self, user_id): params = self._get_validated_object_parameters(request.form, False) user = data_engine.get_user(user_id=user_id) if user is None: raise DoesNotExistError(str(user_id)) user.first_name = params['first_name'] user.last_name = params['last_name'] user.email = params['email'] user.auth_type = params['auth_type'] user.allow_api = params['allow_api'] # Don't update the status field with this method # Update username only if non-LDAP if user.auth_type != User.AUTH_TYPE_LDAP: user.username = params['username'] # Update password only if non-LDAP and a new one was passed in if user.auth_type != User.AUTH_TYPE_LDAP and params['password']: user.set_password(params['password']) data_engine.save_object(user) # Do not give out anything password related udict = object_to_dict(user) del udict['password'] return make_api_success_response(udict)
def post(self, folio_id): db_session = data_engine.db_get_session() try: # Get the portfolio folio = data_engine.get_portfolio(folio_id, _db_session=db_session) if folio is None: raise DoesNotExistError(str(folio_id)) # Check portfolio permissions permissions_engine.ensure_portfolio_permitted( folio, FolioPermission.ACCESS_EDIT, get_session_user()) # Get the image by either ID or src params = self._get_validated_object_parameters(request.form, True) if 'image_id' in params: image = data_engine.get_image(params['image_id'], _db_session=db_session) if image is None: raise DoesNotExistError(str(params['image_id'])) else: image = auto_sync_file(params['image_src'], data_engine, task_engine, anon_history=True, burst_pdf=False, _db_session=db_session) if image is None or image.status == Image.STATUS_DELETED: raise DoesNotExistError(params['image_src']) # Check image permissions permissions_engine.ensure_folder_permitted( image.folder, FolderPermission.ACCESS_VIEW, get_session_user(), False) # Add history first so that we only commit once at the end data_engine.add_portfolio_history(folio, get_session_user(), FolioHistory.ACTION_IMAGE_CHANGE, '%s added' % image.src, _db_session=db_session, _commit=False) # Flag that exported zips are now out of date folio.last_updated = datetime.utcnow() # Add the image and commit changes db_folio_image = data_engine.save_object(FolioImage( folio, image, params['image_parameters'], params['filename'], params['index']), refresh=True, _db_session=db_session, _commit=True) return make_api_success_response( object_to_dict(_prep_folioimage_object(db_folio_image), _omit_fields + ['portfolio'])) finally: db_session.close()
def create_default_template(): from imageserver.flask_app import app, data_engine from imageserver.models import ImageTemplate, Property log('Creating default image template') existing_obj = data_engine.get_image_template(tempname='Default') if existing_obj is None: data_engine.save_object(ImageTemplate( 'Default', 'Defines the system defaults for image generation if the ' 'image does not specify a template or specific parameter value', { 'format': {'value': app.config.get('IMAGE_FORMAT_DEFAULT', '')}, 'quality': {'value': app.config.get('IMAGE_QUALITY_DEFAULT', 80)}, 'strip': {'value': app.config.get('IMAGE_STRIP_DEFAULT', True)}, 'colorspace': {'value': app.config.get('IMAGE_COLORSPACE_DEFAULT', 'RGB')}, 'dpi_x': {'value': app.config.get('IMAGE_DPI_DEFAULT', None)}, 'dpi_y': {'value': app.config.get('IMAGE_DPI_DEFAULT', None)}, 'record_stats': {'value': True}, 'expiry_secs': {'value': app.config.get('IMAGE_EXPIRY_TIME_DEFAULT', 60 * 60 * 24 * 7)} } )) log( 'Info: Default image generation settings have been moved into a ' 'new template called \'Default\'.' ) else: log('Skipped creation of a \'Default\' template as it already exists.') data_engine.save_object(Property(Property.DEFAULT_TEMPLATE, 'default')) log( 'If you have any of the following settings in your local_settings.py ' 'file, they can now be deleted:\n\n' 'IMAGE_FORMAT_DEFAULT\nIMAGE_QUALITY_DEFAULT\nIMAGE_STRIP_DEFAULT\n' 'IMAGE_COLORSPACE_DEFAULT\nIMAGE_DPI_DEFAULT\nIMAGE_EXPIRY_TIME_DEFAULT\n' )
def put(self, group_id): params = self._get_validated_object_parameters(request.form) group = data_engine.get_group(group_id=group_id, load_users=True) if group is None: raise DoesNotExistError(str(group_id)) # Back up the object in case we need to restore it backup_group = copy.deepcopy(group) # Update group group.description = params['description'] if group.group_type != Group.GROUP_TYPE_SYSTEM: group.group_type = params['group_type'] if group.group_type == Group.GROUP_TYPE_LOCAL: group.name = params['name'] permissions_changed = self._set_permissions(group, params) data_engine.save_object(group) # Reset permissions cache if permissions_changed: permissions_engine.reset() _check_for_user_lockout(backup_group) # Do not give out anything password related gdict = object_to_dict(group) for udict in gdict['users']: del udict['password'] return make_api_success_response(gdict)
def import_templates(): from imageserver.flask_app import app, data_engine from imageserver.image_attrs import ImageAttrs from imageserver.models import ImageTemplate from imageserver.template_attrs import TemplateAttrs from imageserver.util import filepath_filename, parse_colour # Find *.cfg num_files = 0 num_errors = 0 num_skipped = 0 template_dir_path = app.config.get( 'TEMPLATES_BASE_DIR', os.path.join(app.config['INSTALL_DIR'], 'templates') ) cfg_files = glob.glob(os.path.join(template_dir_path, '*.cfg')) log('Starting image templates import') merge_def_settings = False if cfg_files: merge_conf = input( '\nQIS v2 removes the system settings for default image format, ' 'quality, DPI, strip, colorspace, and expiry time. These values ' 'now need to be defined in your image templates instead. ' 'Do you want to merge these settings into your templates now? ' 'Y/N (Y recommended)\n' ) merge_def_settings = (merge_conf in ['y', 'Y']) for cfg_file_path in cfg_files: num_files += 1 (template_name, _) = os.path.splitext(filepath_filename(cfg_file_path)) try: # Read config file cp = configparser.RawConfigParser() cp.read(cfg_file_path) # Get image values and put them in an ImageAttrs object section = 'ImageAttributes' t_image_attrs = ImageAttrs( template_name, -1, _config_get(cp, cp.getint, section, 'page'), _config_get(cp, cp.get, section, 'format', True), None, _config_get(cp, cp.getint, section, 'width'), _config_get(cp, cp.getint, section, 'height'), _config_get(cp, cp.get, section, 'halign', True), _config_get(cp, cp.get, section, 'valign', True), _config_get(cp, cp.getfloat, section, 'angle'), _config_get(cp, cp.get, section, 'flip'), _config_get(cp, cp.getfloat, section, 'top'), _config_get(cp, cp.getfloat, section, 'left'), _config_get(cp, cp.getfloat, section, 'bottom'), _config_get(cp, cp.getfloat, section, 'right'), _config_get(cp, cp.getboolean, section, 'autocropfit'), _config_get(cp, cp.getboolean, section, 'autosizefit'), parse_colour(_config_get(cp, cp.get, section, 'fill')), _config_get(cp, cp.getint, section, 'quality'), _config_get(cp, cp.getint, section, 'sharpen'), _config_get(cp, cp.get, section, 'overlay', False), _config_get(cp, cp.getfloat, section, 'ovsize'), _config_get(cp, cp.get, section, 'ovpos', True), _config_get(cp, cp.getfloat, section, 'ovopacity'), _config_get(cp, cp.get, section, 'icc', True), _config_get(cp, cp.get, section, 'intent', True), _config_get(cp, cp.getboolean, section, 'bpc'), _config_get(cp, cp.get, section, 'colorspace', True), _config_get(cp, cp.getboolean, section, 'strip'), _config_get(cp, cp.getint, section, 'dpi'), None ) t_image_attrs.normalise_values() # Get misc options section = 'Miscellaneous' t_stats = _config_get(cp, cp.getboolean, section, 'stats') # Get handling options and create the TemplateAttrs object section = 'BrowserOptions' t_expiry = _config_get(cp, cp.getint, section, 'expiry') t_attach = _config_get(cp, cp.getboolean, section, 'attach') # Get the template as a dict template_dict = { 'expiry_secs': {'value': t_expiry}, 'attachment': {'value': t_attach}, 'record_stats': {'value': t_stats} } ia_dict = t_image_attrs.to_dict() template_dict.update(dict( (k, {'value': v}) for k, v in ia_dict.items() if k not in ['filename', 'template'] )) # Apply the obsolete default image settings to it if merge_def_settings: if not template_dict['format']['value']: template_dict['format']['value'] = app.config.get('IMAGE_FORMAT_DEFAULT') if not template_dict['quality']['value']: template_dict['quality']['value'] = app.config.get('IMAGE_QUALITY_DEFAULT') if template_dict['strip']['value'] is None: template_dict['strip']['value'] = app.config.get('IMAGE_STRIP_DEFAULT') if not template_dict['colorspace']['value']: template_dict['colorspace']['value'] = app.config.get('IMAGE_COLORSPACE_DEFAULT') if not template_dict['dpi_x']['value']: template_dict['dpi_x']['value'] = app.config.get('IMAGE_DPI_DEFAULT') if not template_dict['dpi_y']['value']: template_dict['dpi_y']['value'] = app.config.get('IMAGE_DPI_DEFAULT') if template_dict['expiry_secs']['value'] is None: template_dict['expiry_secs']['value'] = app.config.get('IMAGE_EXPIRY_TIME_DEFAULT', 60 * 60 * 24 * 7) # Record stats needs to default to True in v2.2+ if template_dict['record_stats']['value'] is None: template_dict['record_stats']['value'] = True # Create the TemplateAttrs object template_attrs = TemplateAttrs(template_name, template_dict) # Validate template_attrs.validate() # Import template if it doesn't exist already existing_obj = data_engine.get_image_template(tempname=template_name) if existing_obj is None: log('Importing template \'%s\'' % template_name) data_engine.save_object(ImageTemplate( template_name, 'Imported template', template_attrs.get_raw_dict() )) else: log('Skipped template \'%s\' as it already exists' % template_name) num_skipped += 1 except Exception as e: log('Failed to import template \'%s\' due to: %s' % (template_name, str(e))) num_errors += 1 log('Template import complete, %d file(s) found, ' '%d errors, %d skipped.' % (num_files, num_errors, num_skipped)) if not merge_def_settings: log('Warning: You chose not to merge your v1 default image settings ' 'into your v2 templates. Since the default image settings are ' 'now ignored, some images may be rendered differently.') deleted = False if num_errors == 0 and os.path.exists(template_dir_path): conf = input('\nThe old template files are no longer required. ' + 'Do you want to remove them now? Y/N\n') if conf in ['y', 'Y']: log('Removing directory ' + template_dir_path) try: shutil.rmtree(template_dir_path) log('Old templates removed OK') deleted = True except Exception as e: log('Warning: failed to delete directory: ' + str(e)) if num_files > 0 and not deleted: log('Info: Old template files remain in ' + template_dir_path)