def load_json():
    """
    load json file gvu_stpoelten.json to api
    """

    try:
        with open(working_directory + "/gvu_stpoelten.json", 'r') as jf:
            neu_datetime = list()
            for item in json.load(jf):
                neu_datetime.append({
                    'date':
                    (datetime.strptime(item['date'],
                                       '%Y-%m-%d %H:%M')).replace(tzinfo=None),
                    'garbage_container_type':
                    item['garbage_container_type']
                })
            return neu_datetime

    except FileNotFoundError as e:
        raise exceptions.InternalServerError(
            description="File Not found. Directory: {0}".format(
                working_directory))

    except Exception as e:
        raise exceptions.InternalServerError(description=e)
Exemple #2
0
def get_image_id(request):
    # Get our desired filename.
    uploading_filename = request.form.get("imageFileName")
    if not uploading_filename:
        return exceptions.BadRequest()

    # Ensure we have an image.
    if "jpegData" not in request.files:
        return exceptions.BadRequest()

    # Sanitize for when we write to disk.
    filename = secure_filename(uploading_filename)
    # Necessary as render templates require the original filename with ".jpg" appended.
    # Nobody here is fond of this.
    filename += ".jpg"

    # An image ID has a maximum size of 7.
    unique_id = generate_unique_id(Images, Images.image_id, 7)
    if unique_id == "":
        return exceptions.InternalServerError()

    # Next, save our file to disk.
    jpeg_image = request.files["jpegData"]
    jpeg_image.save(determine_path(current_order.order_id, filename))

    # Finally, save state to the database.
    added_image = Images(
        image_id=unique_id, order_id=current_order.order_id, filename=filename
    )
    db.session.add(added_image)
    db.session.commit()

    return {
        "imageID": unique_id,
    }
Exemple #3
0
    def _proxy_request(self, remote_address, path_info, query_string):
        headers = {
            'X-Forwarded-For': remote_address,
            'X-Instance-ID': self.ip_instance_map.get(remote_address, ''),
            'X-Quantum-Network-ID': self.network_id,
            'X-Tenant-ID': self.tenant_id
        }

        url = urlparse.urlunsplit((
            'http',
            self.orchestrator_loc,
            path_info,
            query_string,
            ''))

        response = requests.get(url, headers=headers)

        if response.status_code == requests.codes.ok:
            LOG.debug(response)
            return wrappers.Response(response.content, mimetype='text/plain')
        elif response.status_code == requests.codes.not_found:
            return exceptions.NotFound()
        elif response.status_code == requests.codes.internal_server_error:
            msg = 'Remote metadata server experienced an error.'
            return exceptions.InternalServerError(description=unicode(msg))
        else:
            raise Exception('Unexpected response code: %s' % response.status)
Exemple #4
0
def post(
    body: typing.Dict[str, typing.Any]
) -> typing.Tuple[typing.Dict[str, typing.Any], int]:
    LOG.info('Received request to create a new user')
    try:
        single_user = user.UserDB.query.filter_by(
            user_name=body['user_name']).one()
        if single_user:
            exceptions.Conflict(
                description='User by this name already exists in the system')
    except exc.NoResultFound:
        LOG.info('User doesn\'t exist, system will add it')

    new_user = user.UserDB(**body)
    new_user.id = str(uuid.uuid4())
    database.db.session.add(new_user)
    try:
        database.db.session.commit()
        LOG.info('Added new user')
    except Exception:
        LOG.exception('Failed to add user')
        database.db.session.rollback()
        exceptions.InternalServerError(
            description='Failed to add new user to the system')
    return user.User(
        id=str(new_user.id),
        userName=new_user.user_name,
        firstName=new_user.first_name,
        lastName=new_user.last_name,
        email=new_user.email,
        address=new_user.address,
        postalCode=new_user.postal_code,
    ).dict(), 201
def load_users_json():
    """
    load users json file 
    """

    try:
        with open(working_directory + "/users.json", 'r') as jf:
            return json.load(jf)['users']

    except FileNotFoundError as e:
        raise exceptions.InternalServerError(
            description="File Not found. Directory: {0}".format(
                working_directory + "/udsers.json"))

    except Exception as e:
        raise exceptions.InternalServerError(description=e)
Exemple #6
0
def portfolio_download(human_id, filename):
    logger.debug('GET ' + request.url)
    try:
        # Find the portfolio
        folio = data_engine.get_portfolio(human_id=human_id)
        if not folio:
            raise DoesNotExistError('Portfolio \'%s\' does not exist' %
                                    human_id)

        # Ensure that the user has permission to download the portfolio
        user = get_session_user()
        permissions_engine.ensure_portfolio_permitted(
            folio, FolioPermission.ACCESS_DOWNLOAD, user)

        # Check that the filename is valid (note: assumes folio.downloads is eager loaded)
        if not filename:
            raise DoesNotExistError('No filename specified')
        folio_exports = [
            dl for dl in folio.downloads if dl.filename == filename
        ]
        if not folio_exports:
            raise DoesNotExistError('Download \'%s\' is not available' %
                                    filename)
        folio_export = folio_exports[0]
        # The physical file should always exist when the data+filename exists
        # This also checks that the file path lies inside IMAGES_BASE_DIR
        zip_path = get_portfolio_export_file_path(folio_export)
        ensure_path_exists(zip_path, require_file=True)

        # Prepare to serve the file
        response = send_file(
            get_abs_path(zip_path),
            mimetype='application/zip',
            as_attachment=True,
            conditional=True,
            cache_timeout=31536000  # zips never change once created
        )

        # Lastly write an audit record
        data_engine.add_portfolio_history(folio, user,
                                          FolioHistory.ACTION_DOWNLOADED,
                                          folio_export.filename)
        return response

    except httpexc.HTTPException:
        # Pass through HTTP 4xx and 5xx
        raise
    except SecurityError as e:
        if app.config['DEBUG']:
            raise
        log_security_error(e, request)
        raise httpexc.Forbidden()
    except DoesNotExistError as e:
        logger.warning('404 Not found: ' + str(e))
        raise httpexc.NotFound(safe_error_str(e))
    except Exception as e:
        if app.config['DEBUG']:
            raise
        logger.error('500 Error for ' + request.url + '\n' + str(e))
        raise httpexc.InternalServerError(safe_error_str(e))
Exemple #7
0
def patch_node(node_id):
    # Parse the request
    node_id = str2id(node_id)
    patch = request.get_json()

    # Find the node type.
    node = mongo.find_one_or_404('nodes', node_id, projection={'node_type': 1})
    try:
        node_type = node['node_type']
    except KeyError:
        msg = 'Node %s has no node_type property' % node_id
        log.warning(msg)
        raise wz_exceptions.InternalServerError(msg)
    log.debug('User %s wants to PATCH %s node %s',
              authentication.current_user_id(), node_type, node_id)

    # Find the PATCH handler for the node type.
    try:
        patch_handler = custom.patch_handlers[node_type]
    except KeyError:
        log.info('No patch handler for node type %r', node_type)
        raise wz_exceptions.MethodNotAllowed(
            'PATCH on node type %r not allowed' % node_type)

    # Let the PATCH handler do its thing.
    return patch_handler(node_id, patch)
Exemple #8
0
    def post(self, entity_id):
        # TODO
        # - read paramterrs
        # - start a session
        # - get a lock of the resource
        # - actuation
        # - verify the actuation
        # - post the updated value to the timeseries database
        # - close the session - abort the session if anything goes wrong.
        args = reqparser.parse_args()
        actuation_value = args.value
        scheduled_time = args.get('scheduled_time', None)
        if scheduled_time:
            # TODO: Implement this
            raise exceptions.NotImplemented(
                'Currently only immediate actuation is implemented.')

        with self.lock_manager.advisory_lock(entity_id) as lock_acquired:
            assert lock_acquired, exceptions.BadRequest(
                'Lock for {0} cannot be acquired'.format(entity_id))
            self.actuation(entity_id, actuation_value)
            actuated_time = arrow.get()
            data = [[entity_id, actuated_time.timestamp, actuation_value]]
            self.ts_db.add_data(data)
            return None

        raise exceptions.InternalServerError('This should not be reached.')
Exemple #9
0
    def render_region (self, request, image):
        """
            Handle request for an image region
        """

        width = int(request.args['w'])
        height = int(request.args['h'])
        x = int(request.args['x'])
        y = int(request.args['y'])
        zoom = int(request.args.get('zoom', "0"))

        # safety limit
        if width * height > MAX_PIXELS:
            raise exceptions.BadRequest("Image size: %d * %d > %d" % (width, height, MAX_PIXELS))

        if zoom > MAX_ZOOM:
            raise exceptions.BadRequest("Image zoom: %d > %d" % (zoom, MAX_ZOOM))

        x = scale_center(x, width, zoom)
        y = scale_center(y, height, zoom)
        
        try:
            return image.tile_mem(width, height, x, y, zoom)

        except pypngtile.Error as error:
            raise exceptions.InternalServerError(str(error))
Exemple #10
0
def post_node_comment(parent_id: bson.ObjectId, markdown_msg: str,
                      attachments: dict):
    parent_node = find_node_or_raise(
        parent_id, 'User %s tried to update comment with bad parent_id %s',
        current_user.objectid, parent_id)

    is_reply = parent_node['node_type'] == 'comment'
    comment = dict(
        parent=parent_id,
        project=parent_node['project'],
        name='Comment',
        user=current_user.objectid,
        node_type='comment',
        properties=dict(
            content=markdown_msg,
            status='published',
            is_reply=is_reply,
            confidence=0,
            rating_positive=0,
            rating_negative=0,
            attachments=attachments,
        ),
        permissions=dict(
            users=[dict(user=current_user.objectid, methods=['PUT'])]))
    r, _, _, status = current_app.post_internal('nodes', comment)

    if status != 201:
        log.warning('Unable to post comment on %s as %s: %s', parent_id,
                    current_user.objectid, r)
        raise wz_exceptions.InternalServerError('Unable to create comment')

    comment_do = get_comment(parent_id, r['_id'])

    return jsonify_data_object(comment_do), 201
def get_image_id(request):
    # Get our desired filename.
    uploading_filename = request.form.get("imageFileName")
    if not uploading_filename:
        return exceptions.BadRequest()

    # Ensure we have an image.
    if "jpegData" not in request.files:
        return exceptions.BadRequest()

    # An image ID has a maximum size of 7.
    unique_id = generate_unique_id(Images, Images.image_id, 7)
    if unique_id == "":
        return exceptions.InternalServerError()

    filename = f"{unique_id}.jpg"

    # Next, save our file to disk.
    jpeg_image = request.files["jpegData"]
    jpeg_image.save(determine_path(current_order.order_id, filename))

    # Finally, save state to the database.
    added_image = Images(image_id=unique_id,
                         order_id=current_order.order_id,
                         filename=filename)
    db.session.add(added_image)
    db.session.commit()

    return {
        "imageID": unique_id,
    }
Exemple #12
0
    def _handle_disposition(self, disp: disposition.Disposition):
        if isinstance(disp, disposition.Redirect):
            # A simple redirection
            return flask.redirect(disp.url)

        if isinstance(disp, disposition.Verified):
            # The user is verified; log them in
            self._session.pop(self._prefill_key, None)

            LOGGER.info("Successful login: %s", disp.identity)
            if self._session_auth_name is not None:
                flask.session.permanent = self.make_permanent
                flask.session[self._session_auth_name] = disp.identity

            if self._on_verified:
                response = self._on_verified(disp)
                if response:
                    return response

            return flask.redirect(disp.redir)

        if isinstance(disp, disposition.Notify):
            # The user needs to take some additional action
            return self._render_notify(disp.cdata)

        if isinstance(disp, disposition.Error):
            # The user's login failed
            return self.render_login_form(destination=disp.redir, error=disp.message)

        # unhandled disposition
        raise http_error.InternalServerError("Unknown disposition type " + str(type(disp)))
Exemple #13
0
    def api_create_task(self, job, commands, name, parents=None, priority=50,
                        status='queued', *, task_type: str) -> bson.ObjectId:
        """Creates a task in MongoDB for the given job, executing commands.

        Returns the ObjectId of the created task.
        """

        task = {
            'job': job['_id'],
            'manager': job['manager'],
            'user': job['user'],
            'name': name,
            'status': status,
            'job_type': job['job_type'],
            'task_type': task_type,
            'commands': [cmd.to_dict() for cmd in commands],
            'job_priority': job['priority'],
            'priority': priority,
            'project': job['project'],
        }
        # Insertion of None parents is not supported
        if parents:
            task['parents'] = parents

        self._log.info('Creating task %s for manager %s, user %s',
                       name, job['manager'], job['user'])

        r, _, _, status = current_app.post_internal('flamenco_tasks', task)
        if status != 201:
            self._log.error('Error %i creating task %s: %s',
                            status, task, r)
            raise wz_exceptions.InternalServerError('Unable to create task')

        return r['_id']
Exemple #14
0
def startup(manager_id, notification):
    from flamenco import current_flamenco
    import uuid
    import datetime

    log.info('Received startup notification from manager %s %s', manager_id,
             notification)

    mngr_coll = current_flamenco.db('managers')
    update_res = mngr_coll.update_one({'_id': manager_id}, {
        '$set': {
            '_updated': datetime.datetime.utcnow(),
            '_etag': uuid.uuid4().hex,
            'url': notification['manager_url'],
            'variables': notification['variables'],
            'path_replacement': notification['path_replacement'],
            'stats.nr_of_workers': notification['nr_of_workers'],
        }
    })
    if update_res.matched_count != 1:
        log.warning('Updating manager %s matched %i documents.', manager_id,
                    update_res.matched_count)
        raise wz_exceptions.InternalServerError(
            'Unable to update manager in database.')

    return '', 204
Exemple #15
0
def _set_latest_revisions(objects):
  """Set latest revision_id for given child_type.

  Args:
    objects: list of snapshot objects with child_id and child_type set.
  """
  pairs = [(o.child_type, o.child_id) for o in objects]
  query = db.session.query(
      func.max(revision.Revision.id, name="id", identifier="id"),
      revision.Revision.resource_type,
      revision.Revision.resource_id,
  ).filter(
      tuple_(
          revision.Revision.resource_type,
          revision.Revision.resource_id,
      ).in_(pairs)
  ).group_by(
      revision.Revision.resource_type,
      revision.Revision.resource_id,
  )
  id_map = {(r_type, r_id): id_ for id_, r_type, r_id in query}
  for o in objects:
    o.revision_id = id_map.get((o.child_type, o.child_id))
    if o.revision_id is None:
      raise exceptions.InternalServerError(errors.MISSING_REVISION)
Exemple #16
0
def error_to_json(error):
    """Converts all errors into proper JSONable exceptions.

    This is required because by contract Decapod API is JSON API
    and not JSON data will break their APIs. This catch-em-all
    error handler is required to fullfil a contract on JSON API.
    """

    if isinstance(error, exceptions.DecapodJSONMixin):
        return error.get_response()

    if isinstance(error, werkzeug.exceptions.HTTPException):
        json_error = exceptions.DecapodJSONMixin()

        json_error.code = error.code
        json_error.description = error.description
        json_error.error_name = str(error)
    else:
        LOG.exception("Unmanaged error: %s", error)
        json_error = exceptions.InternalServerError()

    exc_info = sys.exc_info()
    for plugin in plugins.get_alert_plugins():
        try:
            plugin(flask.g.request_id, error, exc_info)
        except Exception as exc:
            LOG.error("Cannot execute plugin: %s", exc)

    return json_error.get_response()
Exemple #17
0
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument(User.username.key,
                            type=str,
                            required=True,
                            help='You have to include the username!')
        parser.add_argument(User.password.key,
                            type=str,
                            required=True,
                            help='You have to include the password!')

        args = parser.parse_args()

        username = args[User.username.key]
        password = args[User.password.key]

        try:
            new_user = self.user_service.add_user(username, password)
        except SQLAlchemyError as error:
            db.session.rollback()

            if User.query.filter_by(username=username).first() is not None:
                raise exc.BadRequest(
                    'Username {} already existent.'.format(username))

            error = str(error.orig) + " for parameters" + str(error.params)
            print("An error occurred with the DB.", error)
            raise exc.InternalServerError(str(error))

        return new_user, status.HTTP_201_CREATED
Exemple #18
0
def abort_with_error(status):
    """Aborts with the given status, or 500 if the status doesn't indicate an error.

    If the status is < 400, status 500 is used instead.
    """

    abort(status if status // 100 >= 4 else 500)
    raise wz_exceptions.InternalServerError('abort() should have aborted!')
    def testErrorHandlerCanProcessInternalServerError(self):
        """Test error handler can process HTTP error."""
        error_500 = exceptions.InternalServerError()
        resp = error_handler.handle_error(error_500)
        resp_obj = json.loads(resp.data[len(ufo.XSSI_PREFIX):])

        self.assertEqual(error_500.code, resp_obj['code'])
        self.assertEqual(error_500.description, resp_obj['message'])
 def serve_microservice(self, name):
     if not self.endpoints:
         raise exceptions.PreconditionFailed('Not deployed yed!')
     try:
         return self.endpoints[name]['func']()
     except Exception as e:
         logging.exception('EXC!', exc_info=e)
         return exceptions.InternalServerError('\n'.join(e.args))
Exemple #21
0
def create_file_doc_for_upload(project_id, uploaded_file):
    """Creates a secure filename and a document in MongoDB for the file.

    The (project_id, filename) tuple should be unique. If such a document already
    exists, it is updated with the new file.

    :param uploaded_file: file from request.files['form-key']
    :type uploaded_file: werkzeug.datastructures.FileStorage
    :returns: a tuple (file_id, filename, status), where 'filename' is the internal
            filename used on GCS.
    """

    project_id = ObjectId(project_id)

    # Hash the filename with path info to get the internal name. This should
    # be unique for the project.
    # internal_filename = uploaded_file.filename
    _, ext = os.path.splitext(uploaded_file.filename)
    internal_filename = uuid.uuid4().hex + ext

    # For now, we don't support overwriting files, and create a new one every time.
    # # See if we can find a pre-existing file doc.
    # files = current_app.data.driver.db['files']
    # file_doc = files.find_one({'project': project_id,
    #                            'name': internal_filename})
    file_doc = None

    # TODO: at some point do name-based and content-based content-type sniffing.
    new_props = {
        'filename': uploaded_file.filename,
        'content_type': uploaded_file.mimetype,
        'length': uploaded_file.content_length,
        'project': project_id,
        'status': 'uploading'
    }

    if file_doc is None:
        # Create a file document on MongoDB for this file.
        file_doc = create_file_doc(name=internal_filename, **new_props)
        file_fields, _, _, status = current_app.post_internal(
            'files', file_doc)
    else:
        file_doc.update(new_props)
        file_fields, _, _, status = current_app.put_internal(
            'files', remove_private_keys(file_doc))

    if status not in (200, 201):
        log.error(
            'Unable to create new file document in MongoDB, status=%i: %s',
            status, file_fields)
        raise wz_exceptions.InternalServerError()

    log.debug(
        'Created file document %s for uploaded file %s; internal name %s',
        file_fields['_id'], uploaded_file.filename, internal_filename)

    return file_fields['_id'], internal_filename, status
Exemple #22
0
 def error_handler(error):
     if not isinstance(error, exceptions.HTTPException):
         error = exceptions.InternalServerError()
     return response.Response(bootstrap.card(body=_.span[
         _.p(style='color:#888')[error.description or ''],
         _.img(src=flask.url_for('mara_app.static', filename='mara.jpg'
                                 ),
               style='margin-top:30px;max-width:100%;')]),
                              title=f'{error.code}  {error.name}',
                              status=error.code)
    def ErrorHandlerCanProcessCustomError(self):
        """Test error handler can process custom error."""
        setup_needed_error = SetupNeeded()
        werkzeug_error = exceptions.InternalServerError(SetupNeeded.message)

        resp = error_handler.handle_error(setup_needed_error)

        self.assertEqual(werkzeug_error.code, resp[1])
        self.assertTrue(str(werkzeug_error.code) in resp[0].data)
        self.assertTrue(werkzeug_error.message in resp[0].data)
Exemple #24
0
def delete(user_id: str) -> typing.Tuple[typing.Any, int]:
    LOG.info('Received request to delete user')
    single_user = _get_user(user_id)
    try:
        database.db.session.delete(single_user)
        database.db.session.commit()
    except Exception:
        LOG.exception('Failed to delete user')
        exceptions.InternalServerError(description='Failed to delete user')
    return '', 204
Exemple #25
0
def generate_and_store_short_code(node):
    nodes_coll = current_app.data.driver.db['nodes']
    node_id = node['_id']

    log.debug('Creating new short link for node %s', node_id)

    max_attempts = 10
    for attempt in range(1, max_attempts):

        # Generate a new short code
        short_code = create_short_code(node)
        log.debug('Created short code for node %s: %s', node_id, short_code)

        node['short_code'] = short_code

        # Store it in MongoDB
        try:
            result = nodes_coll.update_one(
                {'_id': node_id}, {'$set': {
                    'short_code': short_code
                }})
            break
        except pymongo.errors.DuplicateKeyError:
            log.info(
                'Duplicate key while creating short code, retrying (attempt %i/%i)',
                attempt, max_attempts)
            pass
    else:
        log.error(
            'Unable to find unique short code for node %s after %i attempts, failing!',
            node_id, max_attempts)
        raise wz_exceptions.InternalServerError(
            'Unable to create unique short code for node %s' % node_id)

    # We were able to store a short code, now let's verify the result.
    if result.matched_count != 1:
        log.warning('Unable to update node %s with new short_links=%r',
                    node_id, node['short_code'])
        raise wz_exceptions.InternalServerError(
            'Unable to update node %s with new short links' % node_id)

    return short_code
Exemple #26
0
    def __init__(self, limit):
        self.limit = limit

        # Set defaults
        self.code = 429
        self.body = self.get_body()
        self.headers = self.get_headers()

        # Get the description
        if limit.error_message:
            self.description = limit.error_message if not callable(
                limit.error_message) else limit.error_message()
        else:
            self.description = text_type(limit.limit)

        # If error is given, get body & headers
        if self.limit.error_code:
            self.code = limit.error_code
            exception = exceptions.HTTPException(description=self.description)

            # Some common error codes, can add more here
            if self.code == 400:
                exception = exceptions.BadRequest()
            elif self.code == 401:
                exception = exceptions.Unauthorized()
            elif self.code == 403:
                exception = exceptions.Forbidden()
            elif self.code == 404:
                exception = exceptions.NotFound()
            elif self.code == 405:
                exception = exceptions.MethodNotAllowed()
            elif self.code == 406:
                exception = exceptions.NotAcceptable()
            elif self.code == 418:
                exception = exceptions.ImATeapot()  # <3
            elif self.code == 500:
                exception = exceptions.InternalServerError()
            elif self.code == 501:
                exception = exceptions.NotImplemented()

            # Update body & headers
            self.body = exception.get_body()
            self.headers = exception.get_headers()
        else:
            exception = exceptions.TooManyRequests(
                description=self.description)

            # Update body & headers
            self.body = exception.get_body()
            self.headers = exception.get_headers()
        super(RateLimitExceeded,
              self).__init__(description=self.description,
                             response=Response(self.body, self.code,
                                               self.headers))
    def testUnknowExceptionTypesAreHandled(self):
        """Test that unknown exception types are handled (e.g. custom error).

    setup_config() is not called, thus SetupNeeded error should be thrown.
    """
        setup_needed_error = exceptions.InternalServerError(
            SetupNeeded.message)
        resp = self.client.get(flask.url_for('proxyserver_list'))

        self.assertTrue(str(setup_needed_error.code) in resp.data)
        self.assertTrue(SetupNeeded.message in resp.data)
Exemple #28
0
 def start(self):
     """Mark the current task as running."""
     if self.status == self.PENDING_STATUS:
         self.status = self.RUNNING_STATUS
         db.session.add(self)
         db.session.commit()
     else:
         self.status = self.FAILURE_STATUS
         db.session.add(self)
         db.session.commit()
         raise exceptions.InternalServerError(
             app_errors.PREVIOUS_RUN_FAILED)
Exemple #29
0
 def handle_wrapper(*args, **kwargs):
   """Wrapper for handle exceptions during exporting"""
   try:
     return handle_function(*args, **kwargs)
   except query_exceptions.BadQueryException as exception:
     raise wzg_exceptions.BadRequest(exception.message)
   except wzg_exceptions.Unauthorized as ex:
     raise wzg_exceptions.Unauthorized("%s %s" % (ex.message,
                                                  app_errors.RELOAD_PAGE))
   except errors.HttpError as e:
     message = json.loads(e.content).get("error").get("message")
     if e.resp.code == 401:
       raise wzg_exceptions.Unauthorized("%s %s" % (message,
                                                    app_errors.RELOAD_PAGE))
     raise wzg_exceptions.InternalServerError(message)
   except Exception as e:  # pylint: disable=broad-except
     logger.exception(e.message)
     if settings.TESTING:
       raise
     raise wzg_exceptions.InternalServerError(
         app_errors.INTERNAL_SERVER_ERROR.format(job_type="Export"))
def generate_token(manager_id: str):
    manager_oid = str2id(manager_id)
    manager = mongo.find_one_or_404('flamenco_managers', manager_oid)

    # There are three ways in which a user can get here. One is authenticated via
    # Authorization header (either Bearer token or Basic token:subtoken), and the
    # other is via an already-existing browser session.
    # In the latter case it's a redirect from a Flamenco Manager and we need to
    # check the timeout and HMAC.
    if not request.headers.get('Authorization'):
        hasher = current_flamenco.manager_manager.hasher(manager_oid)
        if hasher is None:
            raise wz_exceptions.InternalServerError(
                'Flamenco Manager not linked to this server')

        expires = request.args.get('expires', '')
        string_to_hash = f'{expires}-{manager_id}'
        hasher.update(string_to_hash.encode('utf8'))
        actual_hmac = hasher.hexdigest()

        query_hmac = request.args.get('hmac', '')
        if not hmac.compare_digest(query_hmac, actual_hmac):
            raise wz_exceptions.Unauthorized('Bad HMAC')

        # Only parse the timestamp after we learned we can trust it.
        expire_timestamp = dateutil.parser.parse(expires)
        validity_seconds_left = (expire_timestamp - utcnow()).total_seconds()
        if validity_seconds_left < 0:
            raise wz_exceptions.Unauthorized('Link expired')
        if validity_seconds_left > 900:
            # Flamenco Manager generates links that are valid for less than a minute, so
            # if it's more than 15 minutes in the future, it's bad.
            raise wz_exceptions.Unauthorized('Link too far in the future')

    user = authentication.current_user()

    if not current_flamenco.manager_manager.user_may_use(mngr_doc=manager):
        log.warning(
            'Account %s called %s for manager %s without access to that manager',
            user.user_id, request.url, manager_oid)
        raise wz_exceptions.Unauthorized()

    jwt = current_flamenco.jwt
    if not jwt.usable:
        raise wz_exceptions.NotImplemented(
            'JWT keystore is not usable at the moment')

    log.info('Generating JWT key for user_id=%s manager_id=%s remote_addr=%s',
             user.user_id, manager_id, request.remote_addr)
    key_for_manager = jwt.generate_key_for_manager(manager_oid, user.user_id)

    return Response(key_for_manager, content_type='text/plain')