text: import uuid
  
  from pyramid import httpexceptions
  from pyramid.security import NO_PERMISSION_REQUIRED, Authenticated
  from pyramid.settings import asbool
  
  from kinto.authorization import RouteFactory
  from kinto.core import get_user_info as core_get_user_info
  from kinto.core.errors import raise_invalid
  from kinto.core.events import ACTIONS
  from kinto.core.storage.exceptions import UnicityError
  from kinto.core.utils import build_request, hmac_digest, instance_uri, reapply_cors, view_lookup
  from kinto.views.buckets import Bucket
  from kinto.views.collections import Collection
  
  
  def create_bucket(request, bucket_id):
      """Create a bucket if it doesn't exists."""
      bucket_put = request.method.lower() == "put" and request.path.endswith("buckets/default")
      # Do nothing if current request will already create the bucket.
      if bucket_put:
          return
  
      # Do not intent to create multiple times per request (e.g. in batch).
      already_created = request.bound_data.setdefault("buckets", {})
      if bucket_id in already_created:
          return
  
      bucket_uri = instance_uri(request, "bucket", id=bucket_id)
      bucket = resource_create_object(request=request, resource_cls=Bucket, uri=bucket_uri)
      already_created[bucket_id] = bucket
  
  
  def create_collection(request, bucket_id):
      # Do nothing if current request does not involve a collection.
      subpath = request.matchdict.get("subpath")
      if not (subpath and subpath.rstrip("/").startswith("collections/")):
          return
  
      collection_id = subpath.split("/")[1]
      collection_uri = instance_uri(request, "collection", bucket_id=bucket_id, id=collection_id)
  
      # Do not intent to create multiple times per request (e.g. in batch).
      already_created = request.bound_data.setdefault("collections", {})
      if collection_uri in already_created:
          return
  
      # Do nothing if current request will already create the collection.
      collection_put = request.method.lower() == "put" and request.path.endswith(collection_id)
      if collection_put:
          return
  
      collection = resource_create_object(
          request=request, resource_cls=Collection, uri=collection_uri
      )
      already_created[collection_uri] = collection
  
  
  def resource_create_object(request, resource_cls, uri):
      """Implicitly create a resource (or fail silently).
  
      In the default bucket, the bucket and collection are implicitly
      created. This helper creates one of those resources using a
      simulated request and context that is appropriate for the
      resource. Also runs create events as though the resource were
      created in a subrequest.
  
      If the resource already exists, do nothing.
  
      """
      resource_name, matchdict = view_lookup(request, uri)
  
      # Build a fake request, mainly used to populate the create events that
      # will be triggered by the resource.
      fakerequest = build_request(request, {"method": "PUT", "path": uri})
      fakerequest.matchdict = matchdict
      fakerequest.bound_data = request.bound_data
      fakerequest.authn_type = request.authn_type
      fakerequest.selected_userid = request.selected_userid
      fakerequest.errors = request.errors
      fakerequest.current_resource_name = resource_name
  
      obj_id = matchdict["id"]
  
      # Fake context, required to instantiate a resource.
      context = RouteFactory(fakerequest)
      context.resource_name = resource_name
      resource = resource_cls(fakerequest, context)
  
      # Check that provided id is valid for this resource.
      if not resource.model.id_generator.match(obj_id):
          error_details = {"location": "path", "description": f"Invalid {resource_name} id"}
          raise_invalid(resource.request, **error_details)
  
      data = {"id": obj_id}
      try:
          obj = resource.model.create_object(data)
      except UnicityError:
          # The record already exists; skip running events
          return {}
  
      # Since the current request is not a resource (but a straight Service),
      # we simulate a request on a resource.
      # This will be used in the resource event payload.
      resource.postprocess(obj, action=ACTIONS.CREATE)
      return obj
  
  
  def default_bucket(request):
      if request.method.lower() == "options":
          path = request.path.replace("default", "unknown")
          subrequest = build_request(request, {"method": "OPTIONS", "path": path})
          return request.invoke_subrequest(subrequest)
  
      if Authenticated not in request.effective_principals:
          # Pass through the forbidden_view_config
          raise httpexceptions.HTTPForbidden()
  
      settings = request.registry.settings
  
      if asbool(settings["readonly"]):
          raise httpexceptions.HTTPMethodNotAllowed()
  
      bucket_id = request.default_bucket_id
  
      # Implicit object creations.
      # Make sure bucket exists
      create_bucket(request, bucket_id)
      # Make sure the collection exists
      create_collection(request, bucket_id)
  
      path = request.path.replace("/buckets/default", f"/buckets/{bucket_id}")
      querystring = request.url[(request.url.index(request.path) + len(request.path)) :]
      try:
          # If 'id' is provided as 'default', replace with actual bucket id.
          body = request.json
          body["data"]["id"] = body["data"]["id"].replace("default", bucket_id)
      except Exception:
          body = request.body or {"data": {}}
      subrequest = build_request(
          request, {"method": request.method, "path": path + querystring, "body": body}
      )
      subrequest.bound_data = request.bound_data
  
      try:
          response = request.invoke_subrequest(subrequest)
      except httpexceptions.HTTPException as error:
          is_redirect = error.status_code < 400
          if error.content_type == "application/json" or is_redirect:
              response = reapply_cors(subrequest, error)
          else:
              # Ask the upper level to format the error.
              raise error
      return response
  
  
  def default_bucket_id(request):
      settings = request.registry.settings
      secret = settings["userid_hmac_secret"]
      # Build the user unguessable bucket_id UUID from its user_id
      digest = hmac_digest(secret, request.prefixed_userid)
      return str(uuid.UUID(digest[:32]))
  
  
  def get_user_info(request):
      user_info = {**core_get_user_info(request), "bucket": request.default_bucket_id}
      return user_info
  
  
  def includeme(config):
      # Redirect default to the right endpoint
      config.add_view(default_bucket, route_name="default_bucket", permission=NO_PERMISSION_REQUIRED)
      config.add_view(
          default_bucket, route_name="default_bucket_collection", permission=NO_PERMISSION_REQUIRED
      )
  
      config.add_route("default_bucket_collection", "/buckets/default/{subpath:.*}")
      config.add_route("default_bucket", "/buckets/default")
  
      # Provide helpers
      config.add_request_method(default_bucket_id, reify=True)
      # Override kinto.core default user info
      config.add_request_method(get_user_info)
  
      config.add_api_capability(
          "default_bucket",
          description="The default bucket is an alias for a personal"
          " bucket where collections are created implicitly.",
          url="https://kinto.readthedocs.io/en/latest/api/1.x/"
          "buckets.html#personal-bucket-default",
      )
  